1 //! A cross-platform Rust API for memory mapped buffers. 2 //! 3 //! The core functionality is provided by either [`Mmap`] or [`MmapMut`], 4 //! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html) 5 //! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html) 6 //! respectively. Both function by dereferencing to a slice, allowing the 7 //! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice 8 //! types. 9 //! 10 //! [`File`]: std::fs::File 11 //! 12 //! # Examples 13 //! 14 //! For simple cases [`Mmap`] can be used directly: 15 //! 16 //! ``` 17 //! use std::fs::File; 18 //! use std::io::Read; 19 //! 20 //! use memmap2::Mmap; 21 //! 22 //! # fn main() -> std::io::Result<()> { 23 //! let mut file = File::open("LICENSE-APACHE")?; 24 //! 25 //! let mut contents = Vec::new(); 26 //! file.read_to_end(&mut contents)?; 27 //! 28 //! let mmap = unsafe { Mmap::map(&file)? }; 29 //! 30 //! assert_eq!(&contents[..], &mmap[..]); 31 //! # Ok(()) 32 //! # } 33 //! ``` 34 //! 35 //! However for cases which require configuration of the mapping, then 36 //! you can use [`MmapOptions`] in order to further configure a mapping 37 //! before you create it. 38 39 #![allow(clippy::len_without_is_empty, clippy::missing_safety_doc)] 40 41 #[cfg_attr(unix, path = "unix.rs")] 42 #[cfg_attr(windows, path = "windows.rs")] 43 #[cfg_attr(not(any(unix, windows)), path = "stub.rs")] 44 mod os; 45 use crate::os::{file_len, MmapInner}; 46 47 #[cfg(unix)] 48 mod advice; 49 #[cfg(unix)] 50 pub use crate::advice::Advice; 51 52 use std::fmt; 53 #[cfg(not(any(unix, windows)))] 54 use std::fs::File; 55 use std::io::{Error, ErrorKind, Result}; 56 use std::isize; 57 use std::mem; 58 use std::ops::{Deref, DerefMut}; 59 #[cfg(unix)] 60 use std::os::unix::io::{AsRawFd, RawFd}; 61 #[cfg(windows)] 62 use std::os::windows::io::{AsRawHandle, RawHandle}; 63 use std::slice; 64 65 #[cfg(not(any(unix, windows)))] 66 pub struct MmapRawDescriptor<'a>(&'a File); 67 68 #[cfg(unix)] 69 pub struct MmapRawDescriptor(RawFd); 70 71 #[cfg(windows)] 72 pub struct MmapRawDescriptor(RawHandle); 73 74 pub trait MmapAsRawDesc { as_raw_desc(&self) -> MmapRawDescriptor75 fn as_raw_desc(&self) -> MmapRawDescriptor; 76 } 77 78 #[cfg(not(any(unix, windows)))] 79 impl MmapAsRawDesc for &File { as_raw_desc(&self) -> MmapRawDescriptor80 fn as_raw_desc(&self) -> MmapRawDescriptor { 81 MmapRawDescriptor(self) 82 } 83 } 84 85 #[cfg(unix)] 86 impl MmapAsRawDesc for RawFd { as_raw_desc(&self) -> MmapRawDescriptor87 fn as_raw_desc(&self) -> MmapRawDescriptor { 88 MmapRawDescriptor(*self) 89 } 90 } 91 92 #[cfg(unix)] 93 impl<'a, T> MmapAsRawDesc for &'a T 94 where 95 T: AsRawFd, 96 { as_raw_desc(&self) -> MmapRawDescriptor97 fn as_raw_desc(&self) -> MmapRawDescriptor { 98 MmapRawDescriptor(self.as_raw_fd()) 99 } 100 } 101 102 #[cfg(windows)] 103 impl MmapAsRawDesc for RawHandle { as_raw_desc(&self) -> MmapRawDescriptor104 fn as_raw_desc(&self) -> MmapRawDescriptor { 105 MmapRawDescriptor(*self) 106 } 107 } 108 109 #[cfg(windows)] 110 impl<'a, T> MmapAsRawDesc for &'a T 111 where 112 T: AsRawHandle, 113 { as_raw_desc(&self) -> MmapRawDescriptor114 fn as_raw_desc(&self) -> MmapRawDescriptor { 115 MmapRawDescriptor(self.as_raw_handle()) 116 } 117 } 118 119 /// A memory map builder, providing advanced options and flags for specifying memory map behavior. 120 /// 121 /// `MmapOptions` can be used to create an anonymous memory map using [`map_anon()`], or a 122 /// file-backed memory map using one of [`map()`], [`map_mut()`], [`map_exec()`], 123 /// [`map_copy()`], or [`map_copy_read_only()`]. 124 /// 125 /// ## Safety 126 /// 127 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 128 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 129 /// out of process. Applications must consider the risk and take appropriate precautions when 130 /// using file-backed maps. Solutions such as file permissions, locks or process-private (e.g. 131 /// unlinked) files exist but are platform specific and limited. 132 /// 133 /// [`map_anon()`]: MmapOptions::map_anon() 134 /// [`map()`]: MmapOptions::map() 135 /// [`map_mut()`]: MmapOptions::map_mut() 136 /// [`map_exec()`]: MmapOptions::map_exec() 137 /// [`map_copy()`]: MmapOptions::map_copy() 138 /// [`map_copy_read_only()`]: MmapOptions::map_copy_read_only() 139 #[derive(Clone, Debug, Default)] 140 pub struct MmapOptions { 141 offset: u64, 142 len: Option<usize>, 143 stack: bool, 144 populate: bool, 145 } 146 147 impl MmapOptions { 148 /// Creates a new set of options for configuring and creating a memory map. 149 /// 150 /// # Example 151 /// 152 /// ``` 153 /// use memmap2::{MmapMut, MmapOptions}; 154 /// # use std::io::Result; 155 /// 156 /// # fn main() -> Result<()> { 157 /// // Create a new memory map builder. 158 /// let mut mmap_options = MmapOptions::new(); 159 /// 160 /// // Configure the memory map builder using option setters, then create 161 /// // a memory map using one of `mmap_options.map_anon`, `mmap_options.map`, 162 /// // `mmap_options.map_mut`, `mmap_options.map_exec`, or `mmap_options.map_copy`: 163 /// let mut mmap: MmapMut = mmap_options.len(36).map_anon()?; 164 /// 165 /// // Use the memory map: 166 /// mmap.copy_from_slice(b"...data to copy to the memory map..."); 167 /// # Ok(()) 168 /// # } 169 /// ``` new() -> MmapOptions170 pub fn new() -> MmapOptions { 171 MmapOptions::default() 172 } 173 174 /// Configures the memory map to start at byte `offset` from the beginning of the file. 175 /// 176 /// This option has no effect on anonymous memory maps. 177 /// 178 /// By default, the offset is 0. 179 /// 180 /// # Example 181 /// 182 /// ``` 183 /// use memmap2::MmapOptions; 184 /// use std::fs::File; 185 /// 186 /// # fn main() -> std::io::Result<()> { 187 /// let mmap = unsafe { 188 /// MmapOptions::new() 189 /// .offset(30) 190 /// .map(&File::open("LICENSE-APACHE")?)? 191 /// }; 192 /// assert_eq!(&b"Apache License"[..], 193 /// &mmap[..14]); 194 /// # Ok(()) 195 /// # } 196 /// ``` offset(&mut self, offset: u64) -> &mut Self197 pub fn offset(&mut self, offset: u64) -> &mut Self { 198 self.offset = offset; 199 self 200 } 201 202 /// Configures the created memory mapped buffer to be `len` bytes long. 203 /// 204 /// This option is mandatory for anonymous memory maps. 205 /// 206 /// For file-backed memory maps, the length will default to the file length. 207 /// 208 /// # Example 209 /// 210 /// ``` 211 /// use memmap2::MmapOptions; 212 /// use std::fs::File; 213 /// 214 /// # fn main() -> std::io::Result<()> { 215 /// let mmap = unsafe { 216 /// MmapOptions::new() 217 /// .len(9) 218 /// .map(&File::open("README.md")?)? 219 /// }; 220 /// assert_eq!(&b"# memmap2"[..], &mmap[..]); 221 /// # Ok(()) 222 /// # } 223 /// ``` len(&mut self, len: usize) -> &mut Self224 pub fn len(&mut self, len: usize) -> &mut Self { 225 self.len = Some(len); 226 self 227 } 228 229 /// Returns the configured length, or the length of the provided file. get_len<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize>230 fn get_len<T: MmapAsRawDesc>(&self, file: &T) -> Result<usize> { 231 self.len.map(Ok).unwrap_or_else(|| { 232 let desc = file.as_raw_desc(); 233 let file_len = file_len(desc.0)?; 234 235 if file_len < self.offset { 236 return Err(Error::new( 237 ErrorKind::InvalidData, 238 "memory map offset is larger than length", 239 )); 240 } 241 let len = file_len - self.offset; 242 243 // Rust's slice cannot be larger than isize::MAX. 244 // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html 245 // 246 // This is not a problem on 64-bit targets, but on 32-bit one 247 // having a file or an anonymous mapping larger than 2GB is quite normal 248 // and we have to prevent it. 249 // 250 // The code below is essentially the same as in Rust's std: 251 // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495 252 if mem::size_of::<usize>() < 8 && len > isize::MAX as u64 { 253 return Err(Error::new( 254 ErrorKind::InvalidData, 255 "memory map length overflows isize", 256 )); 257 } 258 259 Ok(len as usize) 260 }) 261 } 262 263 /// Configures the anonymous memory map to be suitable for a process or thread stack. 264 /// 265 /// This option corresponds to the `MAP_STACK` flag on Linux. It has no effect on Windows. 266 /// 267 /// This option has no effect on file-backed memory maps. 268 /// 269 /// # Example 270 /// 271 /// ``` 272 /// use memmap2::MmapOptions; 273 /// 274 /// # fn main() -> std::io::Result<()> { 275 /// let stack = MmapOptions::new().stack().len(4096).map_anon(); 276 /// # Ok(()) 277 /// # } 278 /// ``` stack(&mut self) -> &mut Self279 pub fn stack(&mut self) -> &mut Self { 280 self.stack = true; 281 self 282 } 283 284 /// Populate (prefault) page tables for a mapping. 285 /// 286 /// For a file mapping, this causes read-ahead on the file. This will help to reduce blocking on page faults later. 287 /// 288 /// This option corresponds to the `MAP_POPULATE` flag on Linux. It has no effect on Windows. 289 /// 290 /// # Example 291 /// 292 /// ``` 293 /// use memmap2::MmapOptions; 294 /// use std::fs::File; 295 /// 296 /// # fn main() -> std::io::Result<()> { 297 /// let file = File::open("LICENSE-MIT")?; 298 /// 299 /// let mmap = unsafe { 300 /// MmapOptions::new().populate().map(&file)? 301 /// }; 302 /// 303 /// assert_eq!(&b"Copyright"[..], &mmap[..9]); 304 /// # Ok(()) 305 /// # } 306 /// ``` populate(&mut self) -> &mut Self307 pub fn populate(&mut self) -> &mut Self { 308 self.populate = true; 309 self 310 } 311 312 /// Creates a read-only memory map backed by a file. 313 /// 314 /// # Errors 315 /// 316 /// This method returns an error when the underlying system call fails, which can happen for a 317 /// variety of reasons, such as when the file is not open with read permissions. 318 /// 319 /// # Example 320 /// 321 /// ``` 322 /// use memmap2::MmapOptions; 323 /// use std::fs::File; 324 /// use std::io::Read; 325 /// 326 /// # fn main() -> std::io::Result<()> { 327 /// let mut file = File::open("LICENSE-APACHE")?; 328 /// 329 /// let mut contents = Vec::new(); 330 /// file.read_to_end(&mut contents)?; 331 /// 332 /// let mmap = unsafe { 333 /// MmapOptions::new().map(&file)? 334 /// }; 335 /// 336 /// assert_eq!(&contents[..], &mmap[..]); 337 /// # Ok(()) 338 /// # } 339 /// ``` map<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>340 pub unsafe fn map<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 341 let desc = file.as_raw_desc(); 342 343 MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate) 344 .map(|inner| Mmap { inner }) 345 } 346 347 /// Creates a readable and executable memory map backed by a file. 348 /// 349 /// # Errors 350 /// 351 /// This method returns an error when the underlying system call fails, which can happen for a 352 /// variety of reasons, such as when the file is not open with read permissions. map_exec<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>353 pub unsafe fn map_exec<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 354 let desc = file.as_raw_desc(); 355 356 MmapInner::map_exec(self.get_len(&file)?, desc.0, self.offset, self.populate) 357 .map(|inner| Mmap { inner }) 358 } 359 360 /// Creates a writeable memory map backed by a file. 361 /// 362 /// # Errors 363 /// 364 /// This method returns an error when the underlying system call fails, which can happen for a 365 /// variety of reasons, such as when the file is not open with read and write permissions. 366 /// 367 /// # Example 368 /// 369 /// ``` 370 /// # extern crate memmap2; 371 /// # extern crate tempfile; 372 /// # 373 /// use std::fs::OpenOptions; 374 /// use std::path::PathBuf; 375 /// 376 /// use memmap2::MmapOptions; 377 /// # 378 /// # fn main() -> std::io::Result<()> { 379 /// # let tempdir = tempfile::tempdir()?; 380 /// let path: PathBuf = /* path to file */ 381 /// # tempdir.path().join("map_mut"); 382 /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; 383 /// file.set_len(13)?; 384 /// 385 /// let mut mmap = unsafe { 386 /// MmapOptions::new().map_mut(&file)? 387 /// }; 388 /// 389 /// mmap.copy_from_slice(b"Hello, world!"); 390 /// # Ok(()) 391 /// # } 392 /// ``` map_mut<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut>393 pub unsafe fn map_mut<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> { 394 let desc = file.as_raw_desc(); 395 396 MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate) 397 .map(|inner| MmapMut { inner }) 398 } 399 400 /// Creates a copy-on-write memory map backed by a file. 401 /// 402 /// Data written to the memory map will not be visible by other processes, 403 /// and will not be carried through to the underlying file. 404 /// 405 /// # Errors 406 /// 407 /// This method returns an error when the underlying system call fails, which can happen for a 408 /// variety of reasons, such as when the file is not open with writable permissions. 409 /// 410 /// # Example 411 /// 412 /// ``` 413 /// use memmap2::MmapOptions; 414 /// use std::fs::File; 415 /// use std::io::Write; 416 /// 417 /// # fn main() -> std::io::Result<()> { 418 /// let file = File::open("LICENSE-APACHE")?; 419 /// let mut mmap = unsafe { MmapOptions::new().map_copy(&file)? }; 420 /// (&mut mmap[..]).write_all(b"Hello, world!")?; 421 /// # Ok(()) 422 /// # } 423 /// ``` map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut>424 pub unsafe fn map_copy<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapMut> { 425 let desc = file.as_raw_desc(); 426 427 MmapInner::map_copy(self.get_len(&file)?, desc.0, self.offset, self.populate) 428 .map(|inner| MmapMut { inner }) 429 } 430 431 /// Creates a copy-on-write read-only memory map backed by a file. 432 /// 433 /// # Errors 434 /// 435 /// This method returns an error when the underlying system call fails, which can happen for a 436 /// variety of reasons, such as when the file is not open with read permissions. 437 /// 438 /// # Example 439 /// 440 /// ``` 441 /// use memmap2::MmapOptions; 442 /// use std::fs::File; 443 /// use std::io::Read; 444 /// 445 /// # fn main() -> std::io::Result<()> { 446 /// let mut file = File::open("README.md")?; 447 /// 448 /// let mut contents = Vec::new(); 449 /// file.read_to_end(&mut contents)?; 450 /// 451 /// let mmap = unsafe { 452 /// MmapOptions::new().map_copy_read_only(&file)? 453 /// }; 454 /// 455 /// assert_eq!(&contents[..], &mmap[..]); 456 /// # Ok(()) 457 /// # } 458 /// ``` map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap>459 pub unsafe fn map_copy_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<Mmap> { 460 let desc = file.as_raw_desc(); 461 462 MmapInner::map_copy_read_only(self.get_len(&file)?, desc.0, self.offset, self.populate) 463 .map(|inner| Mmap { inner }) 464 } 465 466 /// Creates an anonymous memory map. 467 /// 468 /// The memory map length should be configured using [`MmapOptions::len()`] 469 /// before creating an anonymous memory map, otherwise a zero-length mapping 470 /// will be crated. 471 /// 472 /// # Errors 473 /// 474 /// This method returns an error when the underlying system call fails or 475 /// when `len > isize::MAX`. map_anon(&self) -> Result<MmapMut>476 pub fn map_anon(&self) -> Result<MmapMut> { 477 let len = self.len.unwrap_or(0); 478 479 // See get_len() for details. 480 if mem::size_of::<usize>() < 8 && len > isize::MAX as usize { 481 return Err(Error::new( 482 ErrorKind::InvalidData, 483 "memory map length overflows isize", 484 )); 485 } 486 487 MmapInner::map_anon(len, self.stack, self.populate).map(|inner| MmapMut { inner }) 488 } 489 490 /// Creates a raw memory map. 491 /// 492 /// # Errors 493 /// 494 /// This method returns an error when the underlying system call fails, which can happen for a 495 /// variety of reasons, such as when the file is not open with read and write permissions. map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw>496 pub fn map_raw<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> { 497 let desc = file.as_raw_desc(); 498 499 MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate) 500 .map(|inner| MmapRaw { inner }) 501 } 502 503 /// Creates a read-only raw memory map 504 /// 505 /// This is primarily useful to avoid intermediate `Mmap` instances when 506 /// read-only access to files modified elsewhere are required. 507 /// 508 /// # Errors 509 /// 510 /// This method returns an error when the underlying system call fails map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw>511 pub fn map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> { 512 let desc = file.as_raw_desc(); 513 514 MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate) 515 .map(|inner| MmapRaw { inner }) 516 } 517 } 518 519 /// A handle to an immutable memory mapped buffer. 520 /// 521 /// A `Mmap` may be backed by a file, or it can be anonymous map, backed by volatile memory. Use 522 /// [`MmapOptions`] or [`map()`] to create a file-backed memory map. To create an immutable 523 /// anonymous memory map, first create a mutable anonymous memory map, and then make it immutable 524 /// with [`MmapMut::make_read_only()`]. 525 /// 526 /// A file backed `Mmap` is created by `&File` reference, and will remain valid even after the 527 /// `File` is dropped. In other words, the `Mmap` handle is completely independent of the `File` 528 /// used to create it. For consistency, on some platforms this is achieved by duplicating the 529 /// underlying file handle. The memory will be unmapped when the `Mmap` handle is dropped. 530 /// 531 /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping 532 /// the mapped pages into physical memory) though the details of this are platform specific. 533 /// 534 /// `Mmap` is [`Sync`] and [`Send`]. 535 /// 536 /// ## Safety 537 /// 538 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 539 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 540 /// out of process. Applications must consider the risk and take appropriate precautions when using 541 /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) 542 /// files exist but are platform specific and limited. 543 /// 544 /// ## Example 545 /// 546 /// ``` 547 /// use memmap2::MmapOptions; 548 /// use std::io::Write; 549 /// use std::fs::File; 550 /// 551 /// # fn main() -> std::io::Result<()> { 552 /// let file = File::open("README.md")?; 553 /// let mmap = unsafe { MmapOptions::new().map(&file)? }; 554 /// assert_eq!(b"# memmap2", &mmap[0..9]); 555 /// # Ok(()) 556 /// # } 557 /// ``` 558 /// 559 /// See [`MmapMut`] for the mutable version. 560 /// 561 /// [`map()`]: Mmap::map() 562 pub struct Mmap { 563 inner: MmapInner, 564 } 565 566 impl Mmap { 567 /// Creates a read-only memory map backed by a file. 568 /// 569 /// This is equivalent to calling `MmapOptions::new().map(file)`. 570 /// 571 /// # Errors 572 /// 573 /// This method returns an error when the underlying system call fails, which can happen for a 574 /// variety of reasons, such as when the file is not open with read permissions. 575 /// 576 /// # Example 577 /// 578 /// ``` 579 /// use std::fs::File; 580 /// use std::io::Read; 581 /// 582 /// use memmap2::Mmap; 583 /// 584 /// # fn main() -> std::io::Result<()> { 585 /// let mut file = File::open("LICENSE-APACHE")?; 586 /// 587 /// let mut contents = Vec::new(); 588 /// file.read_to_end(&mut contents)?; 589 /// 590 /// let mmap = unsafe { Mmap::map(&file)? }; 591 /// 592 /// assert_eq!(&contents[..], &mmap[..]); 593 /// # Ok(()) 594 /// # } 595 /// ``` map<T: MmapAsRawDesc>(file: T) -> Result<Mmap>596 pub unsafe fn map<T: MmapAsRawDesc>(file: T) -> Result<Mmap> { 597 MmapOptions::new().map(file) 598 } 599 600 /// Transition the memory map to be writable. 601 /// 602 /// If the memory map is file-backed, the file must have been opened with write permissions. 603 /// 604 /// # Errors 605 /// 606 /// This method returns an error when the underlying system call fails, which can happen for a 607 /// variety of reasons, such as when the file is not open with writable permissions. 608 /// 609 /// # Example 610 /// 611 /// ``` 612 /// # extern crate memmap2; 613 /// # extern crate tempfile; 614 /// # 615 /// use memmap2::Mmap; 616 /// use std::ops::DerefMut; 617 /// use std::io::Write; 618 /// # use std::fs::OpenOptions; 619 /// 620 /// # fn main() -> std::io::Result<()> { 621 /// # let tempdir = tempfile::tempdir()?; 622 /// let file = /* file opened with write permissions */ 623 /// # OpenOptions::new() 624 /// # .read(true) 625 /// # .write(true) 626 /// # .create(true) 627 /// # .open(tempdir.path() 628 /// # .join("make_mut"))?; 629 /// # file.set_len(128)?; 630 /// let mmap = unsafe { Mmap::map(&file)? }; 631 /// // ... use the read-only memory map ... 632 /// let mut mut_mmap = mmap.make_mut()?; 633 /// mut_mmap.deref_mut().write_all(b"hello, world!")?; 634 /// # Ok(()) 635 /// # } 636 /// ``` make_mut(mut self) -> Result<MmapMut>637 pub fn make_mut(mut self) -> Result<MmapMut> { 638 self.inner.make_mut()?; 639 Ok(MmapMut { inner: self.inner }) 640 } 641 642 /// Advise OS how this memory map will be accessed. Only supported on Unix. 643 /// 644 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 645 #[cfg(unix)] advise(&self, advice: Advice) -> Result<()>646 pub fn advise(&self, advice: Advice) -> Result<()> { 647 self.inner.advise(advice, 0, self.inner.len()) 648 } 649 650 /// Advise OS how this range of memory map will be accessed. 651 /// 652 /// The offset and length must be in the bounds of the memory map. 653 /// 654 /// Only supported on Unix. 655 /// 656 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 657 #[cfg(unix)] advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()>658 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { 659 self.inner.advise(advice, offset, len) 660 } 661 662 /// Lock the whole memory map into RAM. Only supported on Unix. 663 /// 664 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. 665 #[cfg(unix)] lock(&self) -> Result<()>666 pub fn lock(&self) -> Result<()> { 667 self.inner.lock() 668 } 669 670 /// Unlock the whole memory map. Only supported on Unix. 671 /// 672 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. 673 #[cfg(unix)] unlock(&self) -> Result<()>674 pub fn unlock(&self) -> Result<()> { 675 self.inner.unlock() 676 } 677 678 /// Adjust the size of the memory mapping. 679 /// 680 /// This will try to resize the memory mapping in place. If 681 /// [`RemapOptions::may_move`] is specified it will move the mapping if it 682 /// could not resize in place, otherwise it will error. 683 /// 684 /// Only supported on Linux. 685 /// 686 /// See the [`mremap(2)`] man page. 687 /// 688 /// # Safety 689 /// 690 /// Resizing the memory mapping beyond the end of the mapped file will 691 /// result in UB should you happen to access memory beyond the end of the 692 /// file. 693 /// 694 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html 695 #[cfg(target_os = "linux")] remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()>696 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { 697 self.inner.remap(new_len, options) 698 } 699 } 700 701 #[cfg(feature = "stable_deref_trait")] 702 unsafe impl stable_deref_trait::StableDeref for Mmap {} 703 704 impl Deref for Mmap { 705 type Target = [u8]; 706 707 #[inline] deref(&self) -> &[u8]708 fn deref(&self) -> &[u8] { 709 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } 710 } 711 } 712 713 impl AsRef<[u8]> for Mmap { 714 #[inline] as_ref(&self) -> &[u8]715 fn as_ref(&self) -> &[u8] { 716 self.deref() 717 } 718 } 719 720 impl fmt::Debug for Mmap { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result721 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 722 fmt.debug_struct("Mmap") 723 .field("ptr", &self.as_ptr()) 724 .field("len", &self.len()) 725 .finish() 726 } 727 } 728 729 /// A handle to a raw memory mapped buffer. 730 /// 731 /// This struct never hands out references to its interior, only raw pointers. 732 /// This can be helpful when creating shared memory maps between untrusted processes. 733 pub struct MmapRaw { 734 inner: MmapInner, 735 } 736 737 impl MmapRaw { 738 /// Creates a writeable memory map backed by a file. 739 /// 740 /// This is equivalent to calling `MmapOptions::new().map_raw(file)`. 741 /// 742 /// # Errors 743 /// 744 /// This method returns an error when the underlying system call fails, which can happen for a 745 /// variety of reasons, such as when the file is not open with read and write permissions. map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw>746 pub fn map_raw<T: MmapAsRawDesc>(file: T) -> Result<MmapRaw> { 747 MmapOptions::new().map_raw(file) 748 } 749 750 /// Returns a raw pointer to the memory mapped file. 751 /// 752 /// Before dereferencing this pointer, you have to make sure that the file has not been 753 /// truncated since the memory map was created. 754 /// Avoiding this will not introduce memory safety issues in Rust terms, 755 /// but will cause SIGBUS (or equivalent) signal. 756 #[inline] as_ptr(&self) -> *const u8757 pub fn as_ptr(&self) -> *const u8 { 758 self.inner.ptr() 759 } 760 761 /// Returns an unsafe mutable pointer to the memory mapped file. 762 /// 763 /// Before dereferencing this pointer, you have to make sure that the file has not been 764 /// truncated since the memory map was created. 765 /// Avoiding this will not introduce memory safety issues in Rust terms, 766 /// but will cause SIGBUS (or equivalent) signal. 767 #[inline] as_mut_ptr(&self) -> *mut u8768 pub fn as_mut_ptr(&self) -> *mut u8 { 769 self.inner.ptr() as _ 770 } 771 772 /// Returns the length in bytes of the memory map. 773 /// 774 /// Note that truncating the file can cause the length to change (and render this value unusable). 775 #[inline] len(&self) -> usize776 pub fn len(&self) -> usize { 777 self.inner.len() 778 } 779 780 /// Flushes outstanding memory map modifications to disk. 781 /// 782 /// When this method returns with a non-error result, all outstanding changes to a file-backed 783 /// memory map are guaranteed to be durably stored. The file's metadata (including last 784 /// modification timestamp) may not be updated. 785 /// 786 /// # Example 787 /// 788 /// ``` 789 /// # extern crate memmap2; 790 /// # extern crate tempfile; 791 /// # 792 /// use std::fs::OpenOptions; 793 /// use std::io::Write; 794 /// use std::path::PathBuf; 795 /// use std::slice; 796 /// 797 /// use memmap2::MmapRaw; 798 /// 799 /// # fn main() -> std::io::Result<()> { 800 /// let tempdir = tempfile::tempdir()?; 801 /// let path: PathBuf = /* path to file */ 802 /// # tempdir.path().join("flush"); 803 /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; 804 /// file.set_len(128)?; 805 /// 806 /// let mut mmap = unsafe { MmapRaw::map_raw(&file)? }; 807 /// 808 /// let mut memory = unsafe { slice::from_raw_parts_mut(mmap.as_mut_ptr(), 128) }; 809 /// memory.write_all(b"Hello, world!")?; 810 /// mmap.flush()?; 811 /// # Ok(()) 812 /// # } 813 /// ``` flush(&self) -> Result<()>814 pub fn flush(&self) -> Result<()> { 815 let len = self.len(); 816 self.inner.flush(0, len) 817 } 818 819 /// Asynchronously flushes outstanding memory map modifications to disk. 820 /// 821 /// This method initiates flushing modified pages to durable storage, but it will not wait for 822 /// the operation to complete before returning. The file's metadata (including last 823 /// modification timestamp) may not be updated. flush_async(&self) -> Result<()>824 pub fn flush_async(&self) -> Result<()> { 825 let len = self.len(); 826 self.inner.flush_async(0, len) 827 } 828 829 /// Flushes outstanding memory map modifications in the range to disk. 830 /// 831 /// The offset and length must be in the bounds of the memory map. 832 /// 833 /// When this method returns with a non-error result, all outstanding changes to a file-backed 834 /// memory in the range are guaranteed to be durable stored. The file's metadata (including 835 /// last modification timestamp) may not be updated. It is not guaranteed the only the changes 836 /// in the specified range are flushed; other outstanding changes to the memory map may be 837 /// flushed as well. flush_range(&self, offset: usize, len: usize) -> Result<()>838 pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { 839 self.inner.flush(offset, len) 840 } 841 842 /// Asynchronously flushes outstanding memory map modifications in the range to disk. 843 /// 844 /// The offset and length must be in the bounds of the memory map. 845 /// 846 /// This method initiates flushing modified pages to durable storage, but it will not wait for 847 /// the operation to complete before returning. The file's metadata (including last 848 /// modification timestamp) may not be updated. It is not guaranteed that the only changes 849 /// flushed are those in the specified range; other outstanding changes to the memory map may 850 /// be flushed as well. flush_async_range(&self, offset: usize, len: usize) -> Result<()>851 pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { 852 self.inner.flush_async(offset, len) 853 } 854 855 /// Advise OS how this memory map will be accessed. Only supported on Unix. 856 /// 857 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 858 #[cfg(unix)] advise(&self, advice: Advice) -> Result<()>859 pub fn advise(&self, advice: Advice) -> Result<()> { 860 self.inner.advise(advice, 0, self.inner.len()) 861 } 862 863 /// Advise OS how this range of memory map will be accessed. 864 /// 865 /// The offset and length must be in the bounds of the memory map. 866 /// 867 /// Only supported on Unix. 868 /// 869 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 870 #[cfg(unix)] advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()>871 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { 872 self.inner.advise(advice, offset, len) 873 } 874 875 /// Lock the whole memory map into RAM. Only supported on Unix. 876 /// 877 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. 878 #[cfg(unix)] lock(&self) -> Result<()>879 pub fn lock(&self) -> Result<()> { 880 self.inner.lock() 881 } 882 883 /// Unlock the whole memory map. Only supported on Unix. 884 /// 885 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. 886 #[cfg(unix)] unlock(&self) -> Result<()>887 pub fn unlock(&self) -> Result<()> { 888 self.inner.unlock() 889 } 890 891 /// Adjust the size of the memory mapping. 892 /// 893 /// This will try to resize the memory mapping in place. If 894 /// [`RemapOptions::may_move`] is specified it will move the mapping if it 895 /// could not resize in place, otherwise it will error. 896 /// 897 /// Only supported on Linux. 898 /// 899 /// See the [`mremap(2)`] man page. 900 /// 901 /// # Safety 902 /// 903 /// Resizing the memory mapping beyond the end of the mapped file will 904 /// result in UB should you happen to access memory beyond the end of the 905 /// file. 906 /// 907 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html 908 #[cfg(target_os = "linux")] remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()>909 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { 910 self.inner.remap(new_len, options) 911 } 912 } 913 914 impl fmt::Debug for MmapRaw { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result915 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 916 fmt.debug_struct("MmapRaw") 917 .field("ptr", &self.as_ptr()) 918 .field("len", &self.len()) 919 .finish() 920 } 921 } 922 923 impl From<Mmap> for MmapRaw { from(value: Mmap) -> Self924 fn from(value: Mmap) -> Self { 925 Self { inner: value.inner } 926 } 927 } 928 929 impl From<MmapMut> for MmapRaw { from(value: MmapMut) -> Self930 fn from(value: MmapMut) -> Self { 931 Self { inner: value.inner } 932 } 933 } 934 935 /// A handle to a mutable memory mapped buffer. 936 /// 937 /// A file-backed `MmapMut` buffer may be used to read from or write to a file. An anonymous 938 /// `MmapMut` buffer may be used any place that an in-memory byte buffer is needed. Use 939 /// [`MmapMut::map_mut()`] and [`MmapMut::map_anon()`] to create a mutable memory map of the 940 /// respective types, or [`MmapOptions::map_mut()`] and [`MmapOptions::map_anon()`] if non-default 941 /// options are required. 942 /// 943 /// A file backed `MmapMut` is created by `&File` reference, and will remain valid even after the 944 /// `File` is dropped. In other words, the `MmapMut` handle is completely independent of the `File` 945 /// used to create it. For consistency, on some platforms this is achieved by duplicating the 946 /// underlying file handle. The memory will be unmapped when the `MmapMut` handle is dropped. 947 /// 948 /// Dereferencing and accessing the bytes of the buffer may result in page faults (e.g. swapping 949 /// the mapped pages into physical memory) though the details of this are platform specific. 950 /// 951 /// `Mmap` is [`Sync`] and [`Send`]. 952 /// 953 /// See [`Mmap`] for the immutable version. 954 /// 955 /// ## Safety 956 /// 957 /// All file-backed memory map constructors are marked `unsafe` because of the potential for 958 /// *Undefined Behavior* (UB) using the map if the underlying file is subsequently modified, in or 959 /// out of process. Applications must consider the risk and take appropriate precautions when using 960 /// file-backed maps. Solutions such as file permissions, locks or process-private (e.g. unlinked) 961 /// files exist but are platform specific and limited. 962 pub struct MmapMut { 963 inner: MmapInner, 964 } 965 966 impl MmapMut { 967 /// Creates a writeable memory map backed by a file. 968 /// 969 /// This is equivalent to calling `MmapOptions::new().map_mut(file)`. 970 /// 971 /// # Errors 972 /// 973 /// This method returns an error when the underlying system call fails, which can happen for a 974 /// variety of reasons, such as when the file is not open with read and write permissions. 975 /// 976 /// # Example 977 /// 978 /// ``` 979 /// # extern crate memmap2; 980 /// # extern crate tempfile; 981 /// # 982 /// use std::fs::OpenOptions; 983 /// use std::path::PathBuf; 984 /// 985 /// use memmap2::MmapMut; 986 /// # 987 /// # fn main() -> std::io::Result<()> { 988 /// # let tempdir = tempfile::tempdir()?; 989 /// let path: PathBuf = /* path to file */ 990 /// # tempdir.path().join("map_mut"); 991 /// let file = OpenOptions::new() 992 /// .read(true) 993 /// .write(true) 994 /// .create(true) 995 /// .open(&path)?; 996 /// file.set_len(13)?; 997 /// 998 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; 999 /// 1000 /// mmap.copy_from_slice(b"Hello, world!"); 1001 /// # Ok(()) 1002 /// # } 1003 /// ``` map_mut<T: MmapAsRawDesc>(file: T) -> Result<MmapMut>1004 pub unsafe fn map_mut<T: MmapAsRawDesc>(file: T) -> Result<MmapMut> { 1005 MmapOptions::new().map_mut(file) 1006 } 1007 1008 /// Creates an anonymous memory map. 1009 /// 1010 /// This is equivalent to calling `MmapOptions::new().len(length).map_anon()`. 1011 /// 1012 /// # Errors 1013 /// 1014 /// This method returns an error when the underlying system call fails or 1015 /// when `len > isize::MAX`. map_anon(length: usize) -> Result<MmapMut>1016 pub fn map_anon(length: usize) -> Result<MmapMut> { 1017 MmapOptions::new().len(length).map_anon() 1018 } 1019 1020 /// Flushes outstanding memory map modifications to disk. 1021 /// 1022 /// When this method returns with a non-error result, all outstanding changes to a file-backed 1023 /// memory map are guaranteed to be durably stored. The file's metadata (including last 1024 /// modification timestamp) may not be updated. 1025 /// 1026 /// # Example 1027 /// 1028 /// ``` 1029 /// # extern crate memmap2; 1030 /// # extern crate tempfile; 1031 /// # 1032 /// use std::fs::OpenOptions; 1033 /// use std::io::Write; 1034 /// use std::path::PathBuf; 1035 /// 1036 /// use memmap2::MmapMut; 1037 /// 1038 /// # fn main() -> std::io::Result<()> { 1039 /// # let tempdir = tempfile::tempdir()?; 1040 /// let path: PathBuf = /* path to file */ 1041 /// # tempdir.path().join("flush"); 1042 /// let file = OpenOptions::new().read(true).write(true).create(true).open(&path)?; 1043 /// file.set_len(128)?; 1044 /// 1045 /// let mut mmap = unsafe { MmapMut::map_mut(&file)? }; 1046 /// 1047 /// (&mut mmap[..]).write_all(b"Hello, world!")?; 1048 /// mmap.flush()?; 1049 /// # Ok(()) 1050 /// # } 1051 /// ``` flush(&self) -> Result<()>1052 pub fn flush(&self) -> Result<()> { 1053 let len = self.len(); 1054 self.inner.flush(0, len) 1055 } 1056 1057 /// Asynchronously flushes outstanding memory map modifications to disk. 1058 /// 1059 /// This method initiates flushing modified pages to durable storage, but it will not wait for 1060 /// the operation to complete before returning. The file's metadata (including last 1061 /// modification timestamp) may not be updated. flush_async(&self) -> Result<()>1062 pub fn flush_async(&self) -> Result<()> { 1063 let len = self.len(); 1064 self.inner.flush_async(0, len) 1065 } 1066 1067 /// Flushes outstanding memory map modifications in the range to disk. 1068 /// 1069 /// The offset and length must be in the bounds of the memory map. 1070 /// 1071 /// When this method returns with a non-error result, all outstanding changes to a file-backed 1072 /// memory in the range are guaranteed to be durable stored. The file's metadata (including 1073 /// last modification timestamp) may not be updated. It is not guaranteed the only the changes 1074 /// in the specified range are flushed; other outstanding changes to the memory map may be 1075 /// flushed as well. flush_range(&self, offset: usize, len: usize) -> Result<()>1076 pub fn flush_range(&self, offset: usize, len: usize) -> Result<()> { 1077 self.inner.flush(offset, len) 1078 } 1079 1080 /// Asynchronously flushes outstanding memory map modifications in the range to disk. 1081 /// 1082 /// The offset and length must be in the bounds of the memory map. 1083 /// 1084 /// This method initiates flushing modified pages to durable storage, but it will not wait for 1085 /// the operation to complete before returning. The file's metadata (including last 1086 /// modification timestamp) may not be updated. It is not guaranteed that the only changes 1087 /// flushed are those in the specified range; other outstanding changes to the memory map may 1088 /// be flushed as well. flush_async_range(&self, offset: usize, len: usize) -> Result<()>1089 pub fn flush_async_range(&self, offset: usize, len: usize) -> Result<()> { 1090 self.inner.flush_async(offset, len) 1091 } 1092 1093 /// Returns an immutable version of this memory mapped buffer. 1094 /// 1095 /// If the memory map is file-backed, the file must have been opened with read permissions. 1096 /// 1097 /// # Errors 1098 /// 1099 /// This method returns an error when the underlying system call fails, which can happen for a 1100 /// variety of reasons, such as when the file has not been opened with read permissions. 1101 /// 1102 /// # Example 1103 /// 1104 /// ``` 1105 /// # extern crate memmap2; 1106 /// # 1107 /// use std::io::Write; 1108 /// use std::path::PathBuf; 1109 /// 1110 /// use memmap2::{Mmap, MmapMut}; 1111 /// 1112 /// # fn main() -> std::io::Result<()> { 1113 /// let mut mmap = MmapMut::map_anon(128)?; 1114 /// 1115 /// (&mut mmap[..]).write(b"Hello, world!")?; 1116 /// 1117 /// let mmap: Mmap = mmap.make_read_only()?; 1118 /// # Ok(()) 1119 /// # } 1120 /// ``` make_read_only(mut self) -> Result<Mmap>1121 pub fn make_read_only(mut self) -> Result<Mmap> { 1122 self.inner.make_read_only()?; 1123 Ok(Mmap { inner: self.inner }) 1124 } 1125 1126 /// Transition the memory map to be readable and executable. 1127 /// 1128 /// If the memory map is file-backed, the file must have been opened with execute permissions. 1129 /// 1130 /// On systems with separate instructions and data caches (a category that includes many ARM 1131 /// chips), a platform-specific call may be needed to ensure that the changes are visible to the 1132 /// execution unit (e.g. when using this function to implement a JIT compiler). For more 1133 /// details, see [this ARM write-up](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/caches-and-self-modifying-code) 1134 /// or the `man` page for [`sys_icache_invalidate`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/sys_icache_invalidate.3.html). 1135 /// 1136 /// # Errors 1137 /// 1138 /// This method returns an error when the underlying system call fails, which can happen for a 1139 /// variety of reasons, such as when the file has not been opened with execute permissions. make_exec(mut self) -> Result<Mmap>1140 pub fn make_exec(mut self) -> Result<Mmap> { 1141 self.inner.make_exec()?; 1142 Ok(Mmap { inner: self.inner }) 1143 } 1144 1145 /// Advise OS how this memory map will be accessed. Only supported on Unix. 1146 /// 1147 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 1148 #[cfg(unix)] advise(&self, advice: Advice) -> Result<()>1149 pub fn advise(&self, advice: Advice) -> Result<()> { 1150 self.inner.advise(advice, 0, self.inner.len()) 1151 } 1152 1153 /// Advise OS how this range of memory map will be accessed. 1154 /// 1155 /// The offset and length must be in the bounds of the memory map. 1156 /// 1157 /// Only supported on Unix. 1158 /// 1159 /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. 1160 #[cfg(unix)] advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()>1161 pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { 1162 self.inner.advise(advice, offset, len) 1163 } 1164 1165 /// Lock the whole memory map into RAM. Only supported on Unix. 1166 /// 1167 /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. 1168 #[cfg(unix)] lock(&self) -> Result<()>1169 pub fn lock(&self) -> Result<()> { 1170 self.inner.lock() 1171 } 1172 1173 /// Unlock the whole memory map. Only supported on Unix. 1174 /// 1175 /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. 1176 #[cfg(unix)] unlock(&self) -> Result<()>1177 pub fn unlock(&self) -> Result<()> { 1178 self.inner.unlock() 1179 } 1180 1181 /// Adjust the size of the memory mapping. 1182 /// 1183 /// This will try to resize the memory mapping in place. If 1184 /// [`RemapOptions::may_move`] is specified it will move the mapping if it 1185 /// could not resize in place, otherwise it will error. 1186 /// 1187 /// Only supported on Linux. 1188 /// 1189 /// See the [`mremap(2)`] man page. 1190 /// 1191 /// # Safety 1192 /// 1193 /// Resizing the memory mapping beyond the end of the mapped file will 1194 /// result in UB should you happen to access memory beyond the end of the 1195 /// file. 1196 /// 1197 /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html 1198 #[cfg(target_os = "linux")] remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()>1199 pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> { 1200 self.inner.remap(new_len, options) 1201 } 1202 } 1203 1204 #[cfg(feature = "stable_deref_trait")] 1205 unsafe impl stable_deref_trait::StableDeref for MmapMut {} 1206 1207 impl Deref for MmapMut { 1208 type Target = [u8]; 1209 1210 #[inline] deref(&self) -> &[u8]1211 fn deref(&self) -> &[u8] { 1212 unsafe { slice::from_raw_parts(self.inner.ptr(), self.inner.len()) } 1213 } 1214 } 1215 1216 impl DerefMut for MmapMut { 1217 #[inline] deref_mut(&mut self) -> &mut [u8]1218 fn deref_mut(&mut self) -> &mut [u8] { 1219 unsafe { slice::from_raw_parts_mut(self.inner.mut_ptr(), self.inner.len()) } 1220 } 1221 } 1222 1223 impl AsRef<[u8]> for MmapMut { 1224 #[inline] as_ref(&self) -> &[u8]1225 fn as_ref(&self) -> &[u8] { 1226 self.deref() 1227 } 1228 } 1229 1230 impl AsMut<[u8]> for MmapMut { 1231 #[inline] as_mut(&mut self) -> &mut [u8]1232 fn as_mut(&mut self) -> &mut [u8] { 1233 self.deref_mut() 1234 } 1235 } 1236 1237 impl fmt::Debug for MmapMut { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result1238 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1239 fmt.debug_struct("MmapMut") 1240 .field("ptr", &self.as_ptr()) 1241 .field("len", &self.len()) 1242 .finish() 1243 } 1244 } 1245 1246 /// Options for [`Mmap::remap`] and [`MmapMut::remap`]. 1247 #[derive(Copy, Clone, Default, Debug)] 1248 #[cfg(target_os = "linux")] 1249 pub struct RemapOptions { 1250 may_move: bool, 1251 } 1252 1253 #[cfg(target_os = "linux")] 1254 impl RemapOptions { 1255 /// Creates a mew set of options for resizing a memory map. new() -> Self1256 pub fn new() -> Self { 1257 Self::default() 1258 } 1259 1260 /// Controls whether the memory map can be moved if it is not possible to 1261 /// resize it in place. 1262 /// 1263 /// If false then the memory map is guaranteed to remain at the same 1264 /// address when being resized but attempting to resize will return an 1265 /// error if the new memory map would overlap with something else in the 1266 /// current process' memory. 1267 /// 1268 /// By default this is false. 1269 /// 1270 /// # `may_move` and `StableDeref` 1271 /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and 1272 /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the 1273 /// memory map dereferences to a fixed address, however, calling `remap` 1274 /// with `may_move` set may result in the backing memory of the mapping 1275 /// being moved to a new address. This may cause UB in other code 1276 /// depending on the `StableDeref` guarantees. may_move(mut self, may_move: bool) -> Self1277 pub fn may_move(mut self, may_move: bool) -> Self { 1278 self.may_move = may_move; 1279 self 1280 } 1281 into_flags(self) -> libc::c_int1282 pub(crate) fn into_flags(self) -> libc::c_int { 1283 if self.may_move { 1284 libc::MREMAP_MAYMOVE 1285 } else { 1286 0 1287 } 1288 } 1289 } 1290 1291 #[cfg(test)] 1292 mod test { 1293 extern crate tempfile; 1294 1295 #[cfg(unix)] 1296 use crate::advice::Advice; 1297 use std::fs::{File, OpenOptions}; 1298 use std::io::{Read, Write}; 1299 use std::mem; 1300 #[cfg(unix)] 1301 use std::os::unix::io::AsRawFd; 1302 #[cfg(windows)] 1303 use std::os::windows::fs::OpenOptionsExt; 1304 1305 #[cfg(windows)] 1306 const GENERIC_ALL: u32 = 0x10000000; 1307 1308 use super::{Mmap, MmapMut, MmapOptions}; 1309 1310 #[test] map_file()1311 fn map_file() { 1312 let expected_len = 128; 1313 let tempdir = tempfile::tempdir().unwrap(); 1314 let path = tempdir.path().join("mmap"); 1315 1316 let file = OpenOptions::new() 1317 .read(true) 1318 .write(true) 1319 .create(true) 1320 .open(path) 1321 .unwrap(); 1322 1323 file.set_len(expected_len as u64).unwrap(); 1324 1325 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1326 let len = mmap.len(); 1327 assert_eq!(expected_len, len); 1328 1329 let zeros = vec![0; len]; 1330 let incr: Vec<u8> = (0..len as u8).collect(); 1331 1332 // check that the mmap is empty 1333 assert_eq!(&zeros[..], &mmap[..]); 1334 1335 // write values into the mmap 1336 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1337 1338 // read values back 1339 assert_eq!(&incr[..], &mmap[..]); 1340 } 1341 1342 #[test] 1343 #[cfg(unix)] map_fd()1344 fn map_fd() { 1345 let expected_len = 128; 1346 let tempdir = tempfile::tempdir().unwrap(); 1347 let path = tempdir.path().join("mmap"); 1348 1349 let file = OpenOptions::new() 1350 .read(true) 1351 .write(true) 1352 .create(true) 1353 .open(path) 1354 .unwrap(); 1355 1356 file.set_len(expected_len as u64).unwrap(); 1357 1358 let mut mmap = unsafe { MmapMut::map_mut(file.as_raw_fd()).unwrap() }; 1359 let len = mmap.len(); 1360 assert_eq!(expected_len, len); 1361 1362 let zeros = vec![0; len]; 1363 let incr: Vec<u8> = (0..len as u8).collect(); 1364 1365 // check that the mmap is empty 1366 assert_eq!(&zeros[..], &mmap[..]); 1367 1368 // write values into the mmap 1369 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1370 1371 // read values back 1372 assert_eq!(&incr[..], &mmap[..]); 1373 } 1374 1375 /// Checks that "mapping" a 0-length file derefs to an empty slice. 1376 #[test] map_empty_file()1377 fn map_empty_file() { 1378 let tempdir = tempfile::tempdir().unwrap(); 1379 let path = tempdir.path().join("mmap"); 1380 1381 let file = OpenOptions::new() 1382 .read(true) 1383 .write(true) 1384 .create(true) 1385 .open(path) 1386 .unwrap(); 1387 let mmap = unsafe { Mmap::map(&file).unwrap() }; 1388 assert!(mmap.is_empty()); 1389 assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0); 1390 let mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1391 assert!(mmap.is_empty()); 1392 assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0); 1393 } 1394 1395 #[test] map_anon()1396 fn map_anon() { 1397 let expected_len = 128; 1398 let mut mmap = MmapMut::map_anon(expected_len).unwrap(); 1399 let len = mmap.len(); 1400 assert_eq!(expected_len, len); 1401 1402 let zeros = vec![0; len]; 1403 let incr: Vec<u8> = (0..len as u8).collect(); 1404 1405 // check that the mmap is empty 1406 assert_eq!(&zeros[..], &mmap[..]); 1407 1408 // write values into the mmap 1409 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1410 1411 // read values back 1412 assert_eq!(&incr[..], &mmap[..]); 1413 } 1414 1415 #[test] map_anon_zero_len()1416 fn map_anon_zero_len() { 1417 assert!(MmapOptions::new().map_anon().unwrap().is_empty()) 1418 } 1419 1420 #[test] 1421 #[cfg(target_pointer_width = "32")] map_anon_len_overflow()1422 fn map_anon_len_overflow() { 1423 let res = MmapMut::map_anon(0x80000000); 1424 1425 assert_eq!( 1426 res.unwrap_err().to_string(), 1427 "memory map length overflows isize" 1428 ); 1429 } 1430 1431 #[test] file_write()1432 fn file_write() { 1433 let tempdir = tempfile::tempdir().unwrap(); 1434 let path = tempdir.path().join("mmap"); 1435 1436 let mut file = OpenOptions::new() 1437 .read(true) 1438 .write(true) 1439 .create(true) 1440 .open(path) 1441 .unwrap(); 1442 file.set_len(128).unwrap(); 1443 1444 let write = b"abc123"; 1445 let mut read = [0u8; 6]; 1446 1447 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1448 (&mut mmap[..]).write_all(write).unwrap(); 1449 mmap.flush().unwrap(); 1450 1451 file.read_exact(&mut read).unwrap(); 1452 assert_eq!(write, &read); 1453 } 1454 1455 #[test] flush_range()1456 fn flush_range() { 1457 let tempdir = tempfile::tempdir().unwrap(); 1458 let path = tempdir.path().join("mmap"); 1459 1460 let file = OpenOptions::new() 1461 .read(true) 1462 .write(true) 1463 .create(true) 1464 .open(path) 1465 .unwrap(); 1466 file.set_len(128).unwrap(); 1467 let write = b"abc123"; 1468 1469 let mut mmap = unsafe { 1470 MmapOptions::new() 1471 .offset(2) 1472 .len(write.len()) 1473 .map_mut(&file) 1474 .unwrap() 1475 }; 1476 (&mut mmap[..]).write_all(write).unwrap(); 1477 mmap.flush_async_range(0, write.len()).unwrap(); 1478 mmap.flush_range(0, write.len()).unwrap(); 1479 } 1480 1481 #[test] map_copy()1482 fn map_copy() { 1483 let tempdir = tempfile::tempdir().unwrap(); 1484 let path = tempdir.path().join("mmap"); 1485 1486 let mut file = OpenOptions::new() 1487 .read(true) 1488 .write(true) 1489 .create(true) 1490 .open(path) 1491 .unwrap(); 1492 file.set_len(128).unwrap(); 1493 1494 let nulls = b"\0\0\0\0\0\0"; 1495 let write = b"abc123"; 1496 let mut read = [0u8; 6]; 1497 1498 let mut mmap = unsafe { MmapOptions::new().map_copy(&file).unwrap() }; 1499 1500 (&mut mmap[..]).write_all(write).unwrap(); 1501 mmap.flush().unwrap(); 1502 1503 // The mmap contains the write 1504 (&mmap[..]).read_exact(&mut read).unwrap(); 1505 assert_eq!(write, &read); 1506 1507 // The file does not contain the write 1508 file.read_exact(&mut read).unwrap(); 1509 assert_eq!(nulls, &read); 1510 1511 // another mmap does not contain the write 1512 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1513 (&mmap2[..]).read_exact(&mut read).unwrap(); 1514 assert_eq!(nulls, &read); 1515 } 1516 1517 #[test] map_copy_read_only()1518 fn map_copy_read_only() { 1519 let tempdir = tempfile::tempdir().unwrap(); 1520 let path = tempdir.path().join("mmap"); 1521 1522 let file = OpenOptions::new() 1523 .read(true) 1524 .write(true) 1525 .create(true) 1526 .open(path) 1527 .unwrap(); 1528 file.set_len(128).unwrap(); 1529 1530 let nulls = b"\0\0\0\0\0\0"; 1531 let mut read = [0u8; 6]; 1532 1533 let mmap = unsafe { MmapOptions::new().map_copy_read_only(&file).unwrap() }; 1534 (&mmap[..]).read_exact(&mut read).unwrap(); 1535 assert_eq!(nulls, &read); 1536 1537 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1538 (&mmap2[..]).read_exact(&mut read).unwrap(); 1539 assert_eq!(nulls, &read); 1540 } 1541 1542 #[test] map_offset()1543 fn map_offset() { 1544 let tempdir = tempfile::tempdir().unwrap(); 1545 let path = tempdir.path().join("mmap"); 1546 1547 let file = OpenOptions::new() 1548 .read(true) 1549 .write(true) 1550 .create(true) 1551 .open(path) 1552 .unwrap(); 1553 1554 let offset = u32::MAX as u64 + 2; 1555 let len = 5432; 1556 file.set_len(offset + len as u64).unwrap(); 1557 1558 // Check inferred length mmap. 1559 let mmap = unsafe { MmapOptions::new().offset(offset).map_mut(&file).unwrap() }; 1560 assert_eq!(len, mmap.len()); 1561 1562 // Check explicit length mmap. 1563 let mut mmap = unsafe { 1564 MmapOptions::new() 1565 .offset(offset) 1566 .len(len) 1567 .map_mut(&file) 1568 .unwrap() 1569 }; 1570 assert_eq!(len, mmap.len()); 1571 1572 let zeros = vec![0; len]; 1573 let incr: Vec<_> = (0..len).map(|i| i as u8).collect(); 1574 1575 // check that the mmap is empty 1576 assert_eq!(&zeros[..], &mmap[..]); 1577 1578 // write values into the mmap 1579 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1580 1581 // read values back 1582 assert_eq!(&incr[..], &mmap[..]); 1583 } 1584 1585 #[test] index()1586 fn index() { 1587 let mut mmap = MmapMut::map_anon(128).unwrap(); 1588 mmap[0] = 42; 1589 assert_eq!(42, mmap[0]); 1590 } 1591 1592 #[test] sync_send()1593 fn sync_send() { 1594 let mmap = MmapMut::map_anon(129).unwrap(); 1595 1596 fn is_sync_send<T>(_val: T) 1597 where 1598 T: Sync + Send, 1599 { 1600 } 1601 1602 is_sync_send(mmap); 1603 } 1604 1605 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86(mut mmap: MmapMut)1606 fn jit_x86(mut mmap: MmapMut) { 1607 mmap[0] = 0xB8; // mov eax, 0xAB 1608 mmap[1] = 0xAB; 1609 mmap[2] = 0x00; 1610 mmap[3] = 0x00; 1611 mmap[4] = 0x00; 1612 mmap[5] = 0xC3; // ret 1613 1614 let mmap = mmap.make_exec().expect("make_exec"); 1615 1616 let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) }; 1617 assert_eq!(jitfn(), 0xab); 1618 } 1619 1620 #[test] 1621 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86_anon()1622 fn jit_x86_anon() { 1623 jit_x86(MmapMut::map_anon(4096).unwrap()); 1624 } 1625 1626 #[test] 1627 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] jit_x86_file()1628 fn jit_x86_file() { 1629 let tempdir = tempfile::tempdir().unwrap(); 1630 let mut options = OpenOptions::new(); 1631 #[cfg(windows)] 1632 options.access_mode(GENERIC_ALL); 1633 1634 let file = options 1635 .read(true) 1636 .write(true) 1637 .create(true) 1638 .open(tempdir.path().join("jit_x86")) 1639 .expect("open"); 1640 1641 file.set_len(4096).expect("set_len"); 1642 jit_x86(unsafe { MmapMut::map_mut(&file).expect("map_mut") }); 1643 } 1644 1645 #[test] mprotect_file()1646 fn mprotect_file() { 1647 let tempdir = tempfile::tempdir().unwrap(); 1648 let path = tempdir.path().join("mmap"); 1649 1650 let mut options = OpenOptions::new(); 1651 #[cfg(windows)] 1652 options.access_mode(GENERIC_ALL); 1653 1654 let mut file = options 1655 .read(true) 1656 .write(true) 1657 .create(true) 1658 .open(path) 1659 .expect("open"); 1660 file.set_len(256_u64).expect("set_len"); 1661 1662 let mmap = unsafe { MmapMut::map_mut(&file).expect("map_mut") }; 1663 1664 let mmap = mmap.make_read_only().expect("make_read_only"); 1665 let mut mmap = mmap.make_mut().expect("make_mut"); 1666 1667 let write = b"abc123"; 1668 let mut read = [0u8; 6]; 1669 1670 (&mut mmap[..]).write_all(write).unwrap(); 1671 mmap.flush().unwrap(); 1672 1673 // The mmap contains the write 1674 (&mmap[..]).read_exact(&mut read).unwrap(); 1675 assert_eq!(write, &read); 1676 1677 // The file should contain the write 1678 file.read_exact(&mut read).unwrap(); 1679 assert_eq!(write, &read); 1680 1681 // another mmap should contain the write 1682 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1683 (&mmap2[..]).read_exact(&mut read).unwrap(); 1684 assert_eq!(write, &read); 1685 1686 let mmap = mmap.make_exec().expect("make_exec"); 1687 1688 drop(mmap); 1689 } 1690 1691 #[test] mprotect_copy()1692 fn mprotect_copy() { 1693 let tempdir = tempfile::tempdir().unwrap(); 1694 let path = tempdir.path().join("mmap"); 1695 1696 let mut options = OpenOptions::new(); 1697 #[cfg(windows)] 1698 options.access_mode(GENERIC_ALL); 1699 1700 let mut file = options 1701 .read(true) 1702 .write(true) 1703 .create(true) 1704 .open(path) 1705 .expect("open"); 1706 file.set_len(256_u64).expect("set_len"); 1707 1708 let mmap = unsafe { MmapOptions::new().map_copy(&file).expect("map_mut") }; 1709 1710 let mmap = mmap.make_read_only().expect("make_read_only"); 1711 let mut mmap = mmap.make_mut().expect("make_mut"); 1712 1713 let nulls = b"\0\0\0\0\0\0"; 1714 let write = b"abc123"; 1715 let mut read = [0u8; 6]; 1716 1717 (&mut mmap[..]).write_all(write).unwrap(); 1718 mmap.flush().unwrap(); 1719 1720 // The mmap contains the write 1721 (&mmap[..]).read_exact(&mut read).unwrap(); 1722 assert_eq!(write, &read); 1723 1724 // The file does not contain the write 1725 file.read_exact(&mut read).unwrap(); 1726 assert_eq!(nulls, &read); 1727 1728 // another mmap does not contain the write 1729 let mmap2 = unsafe { MmapOptions::new().map(&file).unwrap() }; 1730 (&mmap2[..]).read_exact(&mut read).unwrap(); 1731 assert_eq!(nulls, &read); 1732 1733 let mmap = mmap.make_exec().expect("make_exec"); 1734 1735 drop(mmap); 1736 } 1737 1738 #[test] mprotect_anon()1739 fn mprotect_anon() { 1740 let mmap = MmapMut::map_anon(256).expect("map_mut"); 1741 1742 let mmap = mmap.make_read_only().expect("make_read_only"); 1743 let mmap = mmap.make_mut().expect("make_mut"); 1744 let mmap = mmap.make_exec().expect("make_exec"); 1745 drop(mmap); 1746 } 1747 1748 #[test] raw()1749 fn raw() { 1750 let tempdir = tempfile::tempdir().unwrap(); 1751 let path = tempdir.path().join("mmapraw"); 1752 1753 let mut options = OpenOptions::new(); 1754 let mut file = options 1755 .read(true) 1756 .write(true) 1757 .create(true) 1758 .open(path) 1759 .expect("open"); 1760 file.write_all(b"abc123").unwrap(); 1761 let mmap = MmapOptions::new().map_raw(&file).unwrap(); 1762 assert_eq!(mmap.len(), 6); 1763 assert!(!mmap.as_ptr().is_null()); 1764 assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a'); 1765 } 1766 1767 #[test] raw_read_only()1768 fn raw_read_only() { 1769 let tempdir = tempfile::tempdir().unwrap(); 1770 let path = tempdir.path().join("mmaprawro"); 1771 1772 File::create(&path).unwrap().write_all(b"abc123").unwrap(); 1773 1774 let mmap = MmapOptions::new() 1775 .map_raw_read_only(&File::open(&path).unwrap()) 1776 .unwrap(); 1777 1778 assert_eq!(mmap.len(), 6); 1779 assert!(!mmap.as_ptr().is_null()); 1780 assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a'); 1781 } 1782 1783 /// Something that relies on StableDeref 1784 #[test] 1785 #[cfg(feature = "stable_deref_trait")] owning_ref()1786 fn owning_ref() { 1787 extern crate owning_ref; 1788 1789 let mut map = MmapMut::map_anon(128).unwrap(); 1790 map[10] = 42; 1791 let owning = owning_ref::OwningRef::new(map); 1792 let sliced = owning.map(|map| &map[10..20]); 1793 assert_eq!(42, sliced[0]); 1794 1795 let map = sliced.into_owner().make_read_only().unwrap(); 1796 let owning = owning_ref::OwningRef::new(map); 1797 let sliced = owning.map(|map| &map[10..20]); 1798 assert_eq!(42, sliced[0]); 1799 } 1800 1801 #[test] 1802 #[cfg(unix)] advise()1803 fn advise() { 1804 let expected_len = 128; 1805 let tempdir = tempfile::tempdir().unwrap(); 1806 let path = tempdir.path().join("mmap_advise"); 1807 1808 let file = OpenOptions::new() 1809 .read(true) 1810 .write(true) 1811 .create(true) 1812 .open(path) 1813 .unwrap(); 1814 1815 file.set_len(expected_len as u64).unwrap(); 1816 1817 // Test MmapMut::advise 1818 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1819 mmap.advise(Advice::random()) 1820 .expect("mmap advising should be supported on unix"); 1821 1822 let len = mmap.len(); 1823 assert_eq!(expected_len, len); 1824 1825 let zeros = vec![0; len]; 1826 let incr: Vec<u8> = (0..len as u8).collect(); 1827 1828 // check that the mmap is empty 1829 assert_eq!(&zeros[..], &mmap[..]); 1830 1831 mmap.advise_range(Advice::sequential(), 0, mmap.len()) 1832 .expect("mmap advising should be supported on unix"); 1833 1834 // write values into the mmap 1835 (&mut mmap[..]).write_all(&incr[..]).unwrap(); 1836 1837 // read values back 1838 assert_eq!(&incr[..], &mmap[..]); 1839 1840 // Set advice and Read from the read-only map 1841 let mmap = unsafe { Mmap::map(&file).unwrap() }; 1842 1843 mmap.advise(Advice::random()) 1844 .expect("mmap advising should be supported on unix"); 1845 1846 // read values back 1847 assert_eq!(&incr[..], &mmap[..]); 1848 } 1849 1850 #[test] 1851 #[cfg(target_os = "linux")] advise_writes_unsafely()1852 fn advise_writes_unsafely() { 1853 let mut mmap = MmapMut::map_anon(4096).unwrap(); 1854 mmap.as_mut().fill(255); 1855 let mmap = mmap.make_read_only().unwrap(); 1856 1857 let a = mmap.as_ref()[0]; 1858 mmap.advise(unsafe { Advice::dont_need() }).unwrap(); 1859 let b = mmap.as_ref()[0]; 1860 1861 assert_eq!(a, 255); 1862 assert_eq!(b, 0); 1863 } 1864 1865 /// Returns true if a non-zero amount of memory is locked. 1866 #[cfg(target_os = "linux")] is_locked() -> bool1867 fn is_locked() -> bool { 1868 let status = &std::fs::read_to_string("/proc/self/status") 1869 .expect("/proc/self/status should be available"); 1870 for line in status.lines() { 1871 if line.starts_with("VmLck:") { 1872 let numbers = line.replace(|c: char| !c.is_ascii_digit(), ""); 1873 return numbers != "0"; 1874 } 1875 } 1876 panic!("cannot get VmLck information") 1877 } 1878 1879 #[test] 1880 #[cfg(unix)] lock()1881 fn lock() { 1882 let tempdir = tempfile::tempdir().unwrap(); 1883 let path = tempdir.path().join("mmap_lock"); 1884 1885 let file = OpenOptions::new() 1886 .read(true) 1887 .write(true) 1888 .create(true) 1889 .open(path) 1890 .unwrap(); 1891 file.set_len(128).unwrap(); 1892 1893 let mmap = unsafe { Mmap::map(&file).unwrap() }; 1894 #[cfg(target_os = "linux")] 1895 assert!(!is_locked()); 1896 1897 mmap.lock().expect("mmap lock should be supported on unix"); 1898 #[cfg(target_os = "linux")] 1899 assert!(is_locked()); 1900 1901 mmap.lock() 1902 .expect("mmap lock again should not cause problems"); 1903 #[cfg(target_os = "linux")] 1904 assert!(is_locked()); 1905 1906 mmap.unlock() 1907 .expect("mmap unlock should be supported on unix"); 1908 #[cfg(target_os = "linux")] 1909 assert!(!is_locked()); 1910 1911 mmap.unlock() 1912 .expect("mmap unlock again should not cause problems"); 1913 #[cfg(target_os = "linux")] 1914 assert!(!is_locked()); 1915 } 1916 1917 #[test] 1918 #[cfg(target_os = "linux")] remap_grow()1919 fn remap_grow() { 1920 use crate::RemapOptions; 1921 1922 let initial_len = 128; 1923 let final_len = 2000; 1924 1925 let zeros = vec![0u8; final_len]; 1926 let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect(); 1927 1928 let file = tempfile::tempfile().unwrap(); 1929 file.set_len(final_len as u64).unwrap(); 1930 1931 let mut mmap = unsafe { MmapOptions::new().len(initial_len).map_mut(&file).unwrap() }; 1932 assert_eq!(mmap.len(), initial_len); 1933 assert_eq!(&mmap[..], &zeros[..initial_len]); 1934 1935 unsafe { 1936 mmap.remap(final_len, RemapOptions::new().may_move(true)) 1937 .unwrap() 1938 }; 1939 1940 // The size should have been updated 1941 assert_eq!(mmap.len(), final_len); 1942 1943 // Should still be all zeros 1944 assert_eq!(&mmap[..], &zeros); 1945 1946 // Write out to the whole expanded slice. 1947 mmap.copy_from_slice(&incr); 1948 } 1949 1950 #[test] 1951 #[cfg(target_os = "linux")] remap_shrink()1952 fn remap_shrink() { 1953 use crate::RemapOptions; 1954 1955 let initial_len = 20000; 1956 let final_len = 400; 1957 1958 let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect(); 1959 1960 let file = tempfile::tempfile().unwrap(); 1961 file.set_len(initial_len as u64).unwrap(); 1962 1963 let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; 1964 assert_eq!(mmap.len(), initial_len); 1965 1966 unsafe { mmap.remap(final_len, RemapOptions::new()).unwrap() }; 1967 assert_eq!(mmap.len(), final_len); 1968 1969 // Check that the mmap is still writable along the slice length 1970 mmap.copy_from_slice(&incr); 1971 } 1972 1973 #[test] 1974 #[cfg(target_os = "linux")] 1975 #[cfg(target_pointer_width = "32")] remap_len_overflow()1976 fn remap_len_overflow() { 1977 use crate::RemapOptions; 1978 1979 let file = tempfile::tempfile().unwrap(); 1980 file.set_len(1024).unwrap(); 1981 let mut mmap = unsafe { MmapOptions::new().len(1024).map(&file).unwrap() }; 1982 1983 let res = unsafe { mmap.remap(0x80000000, RemapOptions::new().may_move(true)) }; 1984 assert_eq!( 1985 res.unwrap_err().to_string(), 1986 "memory map length overflows isize" 1987 ); 1988 1989 assert_eq!(mmap.len(), 1024); 1990 } 1991 1992 #[test] 1993 #[cfg(target_os = "linux")] remap_with_offset()1994 fn remap_with_offset() { 1995 use crate::RemapOptions; 1996 1997 let offset = 77; 1998 let initial_len = 128; 1999 let final_len = 2000; 2000 2001 let zeros = vec![0u8; final_len]; 2002 let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect(); 2003 2004 let file = tempfile::tempfile().unwrap(); 2005 file.set_len(final_len as u64 + offset).unwrap(); 2006 2007 let mut mmap = unsafe { 2008 MmapOptions::new() 2009 .len(initial_len) 2010 .offset(offset) 2011 .map_mut(&file) 2012 .unwrap() 2013 }; 2014 assert_eq!(mmap.len(), initial_len); 2015 assert_eq!(&mmap[..], &zeros[..initial_len]); 2016 2017 unsafe { 2018 mmap.remap(final_len, RemapOptions::new().may_move(true)) 2019 .unwrap() 2020 }; 2021 2022 // The size should have been updated 2023 assert_eq!(mmap.len(), final_len); 2024 2025 // Should still be all zeros 2026 assert_eq!(&mmap[..], &zeros); 2027 2028 // Write out to the whole expanded slice. 2029 mmap.copy_from_slice(&incr); 2030 } 2031 } 2032