1use std::ptr::null_mut;
9
10use libc::c_int;
11use libc::PROT_READ;
12use libc::PROT_WRITE;
13use log::warn;
14
15use super::Error as ErrnoError;
16use crate::pagesize;
17use crate::AsRawDescriptor;
18use crate::Descriptor;
19use crate::MappedRegion;
20use crate::MemoryMapping as CrateMemoryMapping;
21use crate::MemoryMappingBuilder;
22use crate::MmapError as Error;
23use crate::MmapResult as Result;
24use crate::Protection;
25use crate::RawDescriptor;
26use crate::SafeDescriptor;
27
28impl From<Protection> for c_int {
29 #[inline(always)]
30 fn from(p: Protection) -> Self {
31 let mut value = 0;
32 if p.read {
33 value |= PROT_READ
34 }
35 if p.write {
36 value |= PROT_WRITE;
37 }
38 value
39 }
40}
41
42fn validate_includes_range(mmap_size: usize, offset: usize, range_size: usize) -> Result<()> {
45 let end_offset = offset
47 .checked_add(range_size)
48 .ok_or(Error::InvalidAddress)?;
49 if end_offset <= mmap_size {
51 Ok(())
52 } else {
53 Err(Error::InvalidAddress)
54 }
55}
56
57impl dyn MappedRegion {
58 pub fn msync(&self, offset: usize, size: usize) -> Result<()> {
61 validate_includes_range(self.size(), offset, size)?;
62
63 let ret = unsafe {
68 libc::msync(
69 (self.as_ptr() as usize + offset) as *mut libc::c_void,
70 size,
71 libc::MS_SYNC,
72 )
73 };
74 if ret != -1 {
75 Ok(())
76 } else {
77 Err(Error::SystemCallFailed(ErrnoError::last()))
78 }
79 }
80
81 pub fn madvise(&self, offset: usize, size: usize, advice: libc::c_int) -> Result<()> {
84 validate_includes_range(self.size(), offset, size)?;
85
86 let ret = unsafe {
91 libc::madvise(
92 (self.as_ptr() as usize + offset) as *mut libc::c_void,
93 size,
94 advice,
95 )
96 };
97 if ret != -1 {
98 Ok(())
99 } else {
100 Err(Error::SystemCallFailed(ErrnoError::last()))
101 }
102 }
103}
104
105#[derive(Debug)]
108pub struct MemoryMapping {
109 addr: *mut u8,
110 size: usize,
111}
112
113unsafe impl Send for MemoryMapping {}
119unsafe impl Sync for MemoryMapping {}
121
122impl MemoryMapping {
123 pub fn new(size: usize) -> Result<MemoryMapping> {
128 MemoryMapping::new_protection(size, None, Protection::read_write())
129 }
130
131 pub fn new_protection(
138 size: usize,
139 align: Option<u64>,
140 prot: Protection,
141 ) -> Result<MemoryMapping> {
142 unsafe { MemoryMapping::try_mmap(None, size, align, prot.into(), None) }
146 }
147
148 pub fn from_fd(fd: &dyn AsRawDescriptor, size: usize) -> Result<MemoryMapping> {
154 MemoryMapping::from_fd_offset(fd, size, 0)
155 }
156
157 pub fn from_fd_offset(
158 fd: &dyn AsRawDescriptor,
159 size: usize,
160 offset: u64,
161 ) -> Result<MemoryMapping> {
162 MemoryMapping::from_fd_offset_protection(fd, size, offset, Protection::read_write())
163 }
164
165 pub fn from_fd_offset_protection(
173 fd: &dyn AsRawDescriptor,
174 size: usize,
175 offset: u64,
176 prot: Protection,
177 ) -> Result<MemoryMapping> {
178 MemoryMapping::from_fd_offset_protection_populate(fd, size, offset, 0, prot, false)
179 }
180
181 pub fn from_fd_offset_protection_populate(
191 fd: &dyn AsRawDescriptor,
192 size: usize,
193 offset: u64,
194 align: u64,
195 prot: Protection,
196 populate: bool,
197 ) -> Result<MemoryMapping> {
198 unsafe {
202 MemoryMapping::try_mmap_populate(
203 None,
204 size,
205 Some(align),
206 prot.into(),
207 Some((fd, offset)),
208 populate,
209 )
210 }
211 }
212
213 pub unsafe fn new_protection_fixed(
226 addr: *mut u8,
227 size: usize,
228 prot: Protection,
229 ) -> Result<MemoryMapping> {
230 MemoryMapping::try_mmap(Some(addr), size, None, prot.into(), None)
231 }
232
233 pub unsafe fn from_descriptor_offset_protection_fixed(
249 addr: *mut u8,
250 fd: &dyn AsRawDescriptor,
251 size: usize,
252 offset: u64,
253 prot: Protection,
254 ) -> Result<MemoryMapping> {
255 MemoryMapping::try_mmap(Some(addr), size, None, prot.into(), Some((fd, offset)))
256 }
257
258 unsafe fn try_mmap(
260 addr: Option<*mut u8>,
261 size: usize,
262 align: Option<u64>,
263 prot: c_int,
264 fd: Option<(&dyn AsRawDescriptor, u64)>,
265 ) -> Result<MemoryMapping> {
266 MemoryMapping::try_mmap_populate(addr, size, align, prot, fd, false)
267 }
268
269 unsafe fn try_mmap_populate(
272 addr: Option<*mut u8>,
273 size: usize,
274 align: Option<u64>,
275 prot: c_int,
276 fd: Option<(&dyn AsRawDescriptor, u64)>,
277 populate: bool,
278 ) -> Result<MemoryMapping> {
279 let mut flags = libc::MAP_SHARED;
280 if populate {
281 flags |= libc::MAP_POPULATE;
282 }
283 let addr = match addr {
285 Some(addr) => {
286 if (addr as usize) % pagesize() != 0 {
287 return Err(Error::NotPageAligned);
288 }
289 flags |= libc::MAP_FIXED | libc::MAP_NORESERVE;
290 addr as *mut libc::c_void
291 }
292 None => null_mut(),
293 };
294
295 let align = if align.unwrap_or(0) == pagesize() as u64 {
297 Some(0)
298 } else {
299 align
300 };
301
302 let (addr, orig_addr, orig_size) = match align {
304 None | Some(0) => (addr, None, None),
305 Some(align) => {
306 if !addr.is_null() || !align.is_power_of_two() {
307 return Err(Error::InvalidAlignment);
308 }
309 let orig_size = size
310 .checked_add(align as usize)
311 .ok_or(Error::InvalidAlignment)?;
312 let orig_addr = libc::mmap64(
313 null_mut(),
314 orig_size,
315 prot,
316 libc::MAP_PRIVATE | libc::MAP_NORESERVE | libc::MAP_ANONYMOUS,
317 -1,
318 0,
319 );
320 if orig_addr == libc::MAP_FAILED {
321 return Err(Error::SystemCallFailed(ErrnoError::last()));
322 }
323
324 flags |= libc::MAP_FIXED;
325
326 let mask = align - 1;
327 (
328 (orig_addr.wrapping_add(mask as usize) as u64 & !mask) as *mut libc::c_void,
329 Some(orig_addr),
330 Some(orig_size),
331 )
332 }
333 };
334
335 let (fd, offset) = match fd {
338 Some((fd, offset)) => {
339 if offset > libc::off64_t::MAX as u64 {
340 return Err(Error::InvalidOffset);
341 }
342 let seals = unsafe { libc::fcntl(fd.as_raw_descriptor(), libc::F_GET_SEALS) };
347 if (seals >= 0) && (seals & libc::F_SEAL_WRITE != 0) {
348 flags &= !libc::MAP_SHARED;
349 flags |= libc::MAP_PRIVATE;
350 }
351 (fd.as_raw_descriptor(), offset as libc::off64_t)
352 }
353 None => {
354 flags |= libc::MAP_ANONYMOUS | libc::MAP_NORESERVE;
355 (-1, 0)
356 }
357 };
358 let addr = libc::mmap64(addr, size, prot, flags, fd, offset);
359 if addr == libc::MAP_FAILED {
360 return Err(Error::SystemCallFailed(ErrnoError::last()));
361 }
362
363 if let Some(orig_addr) = orig_addr {
365 let mut unmap_start = orig_addr as usize;
366 let mut unmap_end = addr as usize;
367 let mut unmap_size = unmap_end - unmap_start;
368
369 if unmap_size > 0 {
370 libc::munmap(orig_addr, unmap_size);
371 }
372
373 unmap_start = addr as usize + size;
374 unmap_end = orig_addr as usize + orig_size.unwrap();
375 unmap_size = unmap_end - unmap_start;
376
377 if unmap_size > 0 {
378 libc::munmap(unmap_start as *mut libc::c_void, unmap_size);
379 }
380 }
381
382 let _ = libc::madvise(addr, size, libc::MADV_DONTDUMP);
384
385 let _ = libc::madvise(addr, size, libc::MADV_MERGEABLE);
389
390 Ok(MemoryMapping {
391 addr: addr as *mut u8,
392 size,
393 })
394 }
395
396 pub fn use_dontfork(&self) -> Result<()> {
398 let ret = unsafe {
402 libc::madvise(
403 self.as_ptr() as *mut libc::c_void,
404 self.size(),
405 libc::MADV_DONTFORK,
406 )
407 };
408 if ret == -1 {
409 Err(Error::SystemCallFailed(ErrnoError::last()))
410 } else {
411 Ok(())
412 }
413 }
414
415 pub fn use_hugepages(&self) -> Result<()> {
417 const SZ_2M: usize = 2 * 1024 * 1024;
418
419 if self.size() < SZ_2M {
422 return Ok(());
423 }
424
425 let ret = unsafe {
429 libc::madvise(
430 self.as_ptr() as *mut libc::c_void,
431 self.size(),
432 libc::MADV_HUGEPAGE,
433 )
434 };
435 if ret == -1 {
436 Err(Error::SystemCallFailed(ErrnoError::last()))
437 } else {
438 Ok(())
439 }
440 }
441
442 pub fn msync(&self) -> Result<()> {
444 let ret = unsafe {
448 libc::msync(
449 self.as_ptr() as *mut libc::c_void,
450 self.size(),
451 libc::MS_SYNC,
452 )
453 };
454 if ret == -1 {
455 return Err(Error::SystemCallFailed(ErrnoError::last()));
456 }
457 Ok(())
458 }
459
460 pub fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
463 self.range_end(mem_offset, count)
464 .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
465 let ret = unsafe {
468 libc::madvise(
471 (self.addr as usize + mem_offset) as *mut _,
472 count,
473 libc::MADV_REMOVE,
474 )
475 };
476 if ret < 0 {
477 Err(Error::SystemCallFailed(super::Error::last()))
478 } else {
479 Ok(())
480 }
481 }
482
483 pub fn async_prefetch(&self, mem_offset: usize, count: usize) -> Result<()> {
496 self.range_end(mem_offset, count)
498 .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
499 let ret = unsafe {
503 libc::madvise(
504 (self.addr as usize + mem_offset) as *mut _,
505 count,
506 libc::MADV_WILLNEED,
507 )
508 };
509 if ret < 0 {
510 Err(Error::SystemCallFailed(super::Error::last()))
511 } else {
512 Ok(())
513 }
514 }
515
516 pub fn drop_page_cache(&self, mem_offset: usize, count: usize) -> Result<()> {
531 self.range_end(mem_offset, count)
533 .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
534 let ret = unsafe {
537 libc::madvise(
538 (self.addr as usize + mem_offset) as *mut _,
539 count,
540 libc::MADV_DONTNEED,
541 )
542 };
543 if ret < 0 {
544 Err(Error::SystemCallFailed(super::Error::last()))
545 } else {
546 Ok(())
547 }
548 }
549
550 pub fn lock_on_fault(&self, mem_offset: usize, count: usize) -> Result<()> {
561 self.range_end(mem_offset, count)
563 .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
564 let addr = self.addr as usize + mem_offset;
565 let ret = unsafe { libc::mlock2(addr as *mut _, count, libc::MLOCK_ONFAULT) };
569 if ret < 0 {
570 let errno = super::Error::last();
571 warn!(
572 "failed to mlock at {:#x} with length {}: {}",
573 addr as u64,
574 self.size(),
575 errno,
576 );
577 Err(Error::SystemCallFailed(errno))
578 } else {
579 Ok(())
580 }
581 }
582
583 pub fn unlock(&self, mem_offset: usize, count: usize) -> Result<()> {
594 self.range_end(mem_offset, count)
596 .map_err(|_| Error::InvalidRange(mem_offset, count, self.size()))?;
597 let ret = unsafe { libc::munlock((self.addr as usize + mem_offset) as *mut _, count) };
600 if ret < 0 {
601 Err(Error::SystemCallFailed(super::Error::last()))
602 } else {
603 Ok(())
604 }
605 }
606
607 pub(crate) fn range_end(&self, offset: usize, count: usize) -> Result<usize> {
609 let mem_end = offset.checked_add(count).ok_or(Error::InvalidAddress)?;
610 if mem_end > self.size() {
611 return Err(Error::InvalidAddress);
612 }
613 Ok(mem_end)
614 }
615}
616
617unsafe impl MappedRegion for MemoryMapping {
621 fn as_ptr(&self) -> *mut u8 {
622 self.addr
623 }
624
625 fn size(&self) -> usize {
626 self.size
627 }
628}
629
630impl Drop for MemoryMapping {
631 fn drop(&mut self) {
632 unsafe {
636 libc::munmap(self.addr as *mut libc::c_void, self.size);
637 }
638 }
639}
640
641pub struct MemoryMappingArena {
644 addr: *mut u8,
645 size: usize,
646}
647
648unsafe impl Send for MemoryMappingArena {}
654unsafe impl Sync for MemoryMappingArena {}
656
657impl MemoryMappingArena {
658 pub fn new(size: usize) -> Result<MemoryMappingArena> {
663 MemoryMapping::new_protection(size, None, Protection::read()).map(From::from)
665 }
666
667 pub fn new_protection(size: usize, prot: Protection) -> Result<MemoryMappingArena> {
669 MemoryMapping::new_protection(size, None, prot).map(From::from)
670 }
671
672 pub fn add_anon_protection(
680 &mut self,
681 offset: usize,
682 size: usize,
683 prot: Protection,
684 ) -> Result<()> {
685 self.try_add(offset, size, prot, None)
686 }
687
688 pub fn add_anon(&mut self, offset: usize, size: usize) -> Result<()> {
695 self.add_anon_protection(offset, size, Protection::read_write())
696 }
697
698 pub fn add_fd(&mut self, offset: usize, size: usize, fd: &dyn AsRawDescriptor) -> Result<()> {
706 self.add_fd_offset(offset, size, fd, 0)
707 }
708
709 pub fn add_fd_offset(
718 &mut self,
719 offset: usize,
720 size: usize,
721 fd: &dyn AsRawDescriptor,
722 fd_offset: u64,
723 ) -> Result<()> {
724 self.add_fd_offset_protection(offset, size, fd, fd_offset, Protection::read_write())
725 }
726
727 pub fn add_fd_offset_protection(
738 &mut self,
739 offset: usize,
740 size: usize,
741 fd: &dyn AsRawDescriptor,
742 fd_offset: u64,
743 prot: Protection,
744 ) -> Result<()> {
745 self.try_add(offset, size, prot, Some((fd, fd_offset)))
746 }
747
748 fn try_add(
751 &mut self,
752 offset: usize,
753 size: usize,
754 prot: Protection,
755 fd: Option<(&dyn AsRawDescriptor, u64)>,
756 ) -> Result<()> {
757 if offset % pagesize() != 0 {
759 return Err(Error::NotPageAligned);
760 }
761 validate_includes_range(self.size(), offset, size)?;
762
763 let mmap = unsafe {
766 match fd {
767 Some((fd, fd_offset)) => MemoryMapping::from_descriptor_offset_protection_fixed(
768 self.addr.add(offset),
769 fd,
770 size,
771 fd_offset,
772 prot,
773 )?,
774 None => MemoryMapping::new_protection_fixed(self.addr.add(offset), size, prot)?,
775 }
776 };
777
778 std::mem::forget(mmap);
780 Ok(())
781 }
782
783 pub fn remove(&mut self, offset: usize, size: usize) -> Result<()> {
790 self.try_add(offset, size, Protection::read(), None)
791 }
792}
793
794unsafe impl MappedRegion for MemoryMappingArena {
798 fn as_ptr(&self) -> *mut u8 {
799 self.addr
800 }
801
802 fn size(&self) -> usize {
803 self.size
804 }
805
806 fn add_fd_mapping(
807 &mut self,
808 offset: usize,
809 size: usize,
810 fd: &dyn AsRawDescriptor,
811 fd_offset: u64,
812 prot: Protection,
813 ) -> Result<()> {
814 self.add_fd_offset_protection(offset, size, fd, fd_offset, prot)
815 }
816
817 fn remove_mapping(&mut self, offset: usize, size: usize) -> Result<()> {
818 self.remove(offset, size)
819 }
820}
821
822impl From<MemoryMapping> for MemoryMappingArena {
823 fn from(mmap: MemoryMapping) -> Self {
824 let addr = mmap.as_ptr();
825 let size = mmap.size();
826
827 std::mem::forget(mmap);
830 MemoryMappingArena { addr, size }
831 }
832}
833
834impl From<CrateMemoryMapping> for MemoryMappingArena {
835 fn from(mmap: CrateMemoryMapping) -> Self {
836 MemoryMappingArena::from(mmap.mapping)
837 }
838}
839
840impl Drop for MemoryMappingArena {
841 fn drop(&mut self) {
842 unsafe {
846 libc::munmap(self.addr as *mut libc::c_void, self.size);
847 }
848 }
849}
850
851impl CrateMemoryMapping {
852 pub fn use_dontfork(&self) -> Result<()> {
853 self.mapping.use_dontfork()
854 }
855
856 pub fn use_hugepages(&self) -> Result<()> {
857 self.mapping.use_hugepages()
858 }
859
860 pub fn from_raw_ptr(addr: RawDescriptor, size: usize) -> Result<CrateMemoryMapping> {
861 MemoryMapping::from_fd_offset(&Descriptor(addr), size, 0).map(|mapping| {
862 CrateMemoryMapping {
863 mapping,
864 _file_descriptor: None,
865 }
866 })
867 }
868}
869
870pub trait MemoryMappingUnix {
871 fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()>;
873 fn async_prefetch(&self, mem_offset: usize, count: usize) -> Result<()>;
875 fn drop_page_cache(&self, mem_offset: usize, count: usize) -> Result<()>;
877 fn lock_on_fault(&self, mem_offset: usize, count: usize) -> Result<()>;
879 fn unlock(&self, mem_offset: usize, count: usize) -> Result<()>;
881 fn lock_all(&self) -> Result<()>;
883}
884
885impl MemoryMappingUnix for CrateMemoryMapping {
886 fn remove_range(&self, mem_offset: usize, count: usize) -> Result<()> {
887 self.mapping.remove_range(mem_offset, count)
888 }
889 fn async_prefetch(&self, mem_offset: usize, count: usize) -> Result<()> {
890 self.mapping.async_prefetch(mem_offset, count)
891 }
892 fn drop_page_cache(&self, mem_offset: usize, count: usize) -> Result<()> {
893 self.mapping.drop_page_cache(mem_offset, count)
894 }
895 fn lock_on_fault(&self, mem_offset: usize, count: usize) -> Result<()> {
896 self.mapping.lock_on_fault(mem_offset, count)
897 }
898 fn unlock(&self, mem_offset: usize, count: usize) -> Result<()> {
899 self.mapping.unlock(mem_offset, count)
900 }
901 fn lock_all(&self) -> Result<()> {
902 self.mapping.lock_on_fault(0, self.mapping.size())
903 }
904}
905
906pub trait MemoryMappingBuilderUnix<'a> {
907 #[allow(clippy::wrong_self_convention)]
908 fn from_descriptor(self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder<'a>;
909}
910
911impl<'a> MemoryMappingBuilderUnix<'a> for MemoryMappingBuilder<'a> {
912 #[allow(clippy::wrong_self_convention)]
916 fn from_descriptor(mut self, descriptor: &'a dyn AsRawDescriptor) -> MemoryMappingBuilder<'a> {
917 self.descriptor = Some(descriptor);
918 self
919 }
920}
921
922impl<'a> MemoryMappingBuilder<'a> {
923 pub fn populate(mut self) -> MemoryMappingBuilder<'a> {
927 self.populate = true;
928 self
929 }
930
931 pub fn build(self) -> Result<CrateMemoryMapping> {
933 match self.descriptor {
934 None => {
935 if self.populate {
936 return Err(Error::InvalidArgument);
938 }
939 MemoryMappingBuilder::wrap(
940 MemoryMapping::new_protection(
941 self.size,
942 self.align,
943 self.protection.unwrap_or_else(Protection::read_write),
944 )?,
945 None,
946 )
947 }
948 Some(descriptor) => MemoryMappingBuilder::wrap(
949 MemoryMapping::from_fd_offset_protection_populate(
950 descriptor,
951 self.size,
952 self.offset.unwrap_or(0),
953 self.align.unwrap_or(0),
954 self.protection.unwrap_or_else(Protection::read_write),
955 self.populate,
956 )?,
957 None,
958 ),
959 }
960 }
961
962 pub(crate) fn wrap(
963 mapping: MemoryMapping,
964 file_descriptor: Option<&'a dyn AsRawDescriptor>,
965 ) -> Result<CrateMemoryMapping> {
966 let file_descriptor = match file_descriptor {
967 Some(descriptor) => Some(
968 SafeDescriptor::try_from(descriptor)
969 .map_err(|_| Error::SystemCallFailed(ErrnoError::last()))?,
970 ),
971 None => None,
972 };
973 Ok(CrateMemoryMapping {
974 mapping,
975 _file_descriptor: file_descriptor,
976 })
977 }
978}
979
980#[cfg(test)]
981mod tests {
982 use tempfile::tempfile;
983
984 use super::*;
985 use crate::descriptor::Descriptor;
986 use crate::VolatileMemory;
987 use crate::VolatileMemoryError;
988
989 #[test]
990 fn basic_map() {
991 let m = MemoryMappingBuilder::new(1024).build().unwrap();
992 assert_eq!(1024, m.size());
993 }
994
995 #[test]
996 fn map_invalid_size() {
997 let res = MemoryMappingBuilder::new(0).build().unwrap_err();
998 if let Error::SystemCallFailed(e) = res {
999 assert_eq!(e.errno(), libc::EINVAL);
1000 } else {
1001 panic!("unexpected error: {res}");
1002 }
1003 }
1004
1005 #[test]
1006 fn map_invalid_fd() {
1007 let fd = Descriptor(-1);
1008 let res = MemoryMapping::from_fd(&fd, 1024).unwrap_err();
1009 if let Error::SystemCallFailed(e) = res {
1010 assert_eq!(e.errno(), libc::EBADF);
1011 } else {
1012 panic!("unexpected error: {res}");
1013 }
1014 }
1015
1016 #[test]
1017 fn test_write_past_end() {
1018 let m = MemoryMappingBuilder::new(5).build().unwrap();
1019 let res = m.write_slice(&[1, 2, 3, 4, 5, 6], 0);
1020 assert!(res.is_ok());
1021 assert_eq!(res.unwrap(), 5);
1022 }
1023
1024 #[test]
1025 fn slice_size() {
1026 let m = MemoryMappingBuilder::new(5).build().unwrap();
1027 let s = m.get_slice(2, 3).unwrap();
1028 assert_eq!(s.size(), 3);
1029 }
1030
1031 #[test]
1032 fn slice_addr() {
1033 let m = MemoryMappingBuilder::new(5).build().unwrap();
1034 let s = m.get_slice(2, 3).unwrap();
1035 assert_eq!(s.as_ptr(), unsafe { m.as_ptr().offset(2) });
1037 }
1038
1039 #[test]
1040 fn slice_overflow_error() {
1041 let m = MemoryMappingBuilder::new(5).build().unwrap();
1042 let res = m.get_slice(usize::MAX, 3).unwrap_err();
1043 assert_eq!(
1044 res,
1045 VolatileMemoryError::Overflow {
1046 base: usize::MAX,
1047 offset: 3,
1048 }
1049 );
1050 }
1051 #[test]
1052 fn slice_oob_error() {
1053 let m = MemoryMappingBuilder::new(5).build().unwrap();
1054 let res = m.get_slice(3, 3).unwrap_err();
1055 assert_eq!(res, VolatileMemoryError::OutOfBounds { addr: 6 });
1056 }
1057
1058 #[test]
1059 fn from_fd_offset_invalid() {
1060 let fd = tempfile().unwrap();
1061 let res =
1062 MemoryMapping::from_fd_offset(&fd, 4096, (libc::off64_t::MAX as u64) + 1).unwrap_err();
1063 match res {
1064 Error::InvalidOffset => {}
1065 e => panic!("unexpected error: {e}"),
1066 }
1067 }
1068
1069 #[test]
1070 fn map_align_overflow() {
1071 let res = MemoryMappingBuilder::new(usize::MAX)
1072 .align(pagesize() as u64 * 2)
1073 .build()
1074 .unwrap_err();
1075 match res {
1076 Error::InvalidAlignment => {}
1077 e => panic!("unexpected error: {e}"),
1078 }
1079 }
1080
1081 #[test]
1082 fn arena_new() {
1083 let m = MemoryMappingArena::new(0x40000).unwrap();
1084 assert_eq!(m.size(), 0x40000);
1085 }
1086
1087 #[test]
1088 fn arena_add() {
1089 let mut m = MemoryMappingArena::new(0x40000).unwrap();
1090 assert!(m.add_anon(0, pagesize() * 4).is_ok());
1091 }
1092
1093 #[test]
1094 fn arena_remove() {
1095 let mut m = MemoryMappingArena::new(0x40000).unwrap();
1096 assert!(m.add_anon(0, pagesize() * 4).is_ok());
1097 assert!(m.remove(0, pagesize()).is_ok());
1098 assert!(m.remove(0, pagesize() * 2).is_ok());
1099 }
1100
1101 #[test]
1102 fn arena_add_alignment_error() {
1103 let mut m = MemoryMappingArena::new(pagesize() * 2).unwrap();
1104 assert!(m.add_anon(0, 0x100).is_ok());
1105 let res = m.add_anon(pagesize() + 1, 0x100).unwrap_err();
1106 match res {
1107 Error::NotPageAligned => {}
1108 e => panic!("unexpected error: {e}"),
1109 }
1110 }
1111
1112 #[test]
1113 fn arena_add_oob_error() {
1114 let mut m = MemoryMappingArena::new(pagesize()).unwrap();
1115 let res = m.add_anon(0, pagesize() + 1).unwrap_err();
1116 match res {
1117 Error::InvalidAddress => {}
1118 e => panic!("unexpected error: {e}"),
1119 }
1120 }
1121
1122 #[test]
1123 fn arena_add_overlapping() {
1124 let ps = pagesize();
1125 let mut m =
1126 MemoryMappingArena::new(12 * ps).expect("failed to create `MemoryMappingArena`");
1127 m.add_anon(ps * 4, ps * 4)
1128 .expect("failed to add sub-mapping");
1129
1130 m.add_anon(ps * 2, ps * 3)
1132 .expect("failed to add front overlapping sub-mapping");
1133
1134 m.add_anon(ps * 7, ps * 3)
1136 .expect("failed to add back overlapping sub-mapping");
1137
1138 m.add_anon(ps * 3, ps * 6)
1141 .expect("failed to add mapping that overlaps several mappings");
1142 }
1143
1144 #[test]
1145 fn arena_remove_overlapping() {
1146 let ps = pagesize();
1147 let mut m =
1148 MemoryMappingArena::new(12 * ps).expect("failed to create `MemoryMappingArena`");
1149 m.add_anon(ps * 4, ps * 4)
1150 .expect("failed to add sub-mapping");
1151 m.add_anon(ps * 2, ps * 2)
1152 .expect("failed to add front overlapping sub-mapping");
1153 m.add_anon(ps * 8, ps * 2)
1154 .expect("failed to add back overlapping sub-mapping");
1155
1156 m.remove(ps * 3, ps * 2)
1158 .expect("failed to remove front overlapping mapping");
1159
1160 m.remove(ps * 7, ps * 2)
1162 .expect("failed to remove back overlapping mapping");
1163
1164 m.remove(ps * 5, ps * 2)
1166 .expect("failed to remove fully overlapping mapping");
1167 }
1168
1169 #[test]
1170 fn arena_remove_unaligned() {
1171 let ps = pagesize();
1172 let mut m =
1173 MemoryMappingArena::new(12 * ps).expect("failed to create `MemoryMappingArena`");
1174
1175 m.add_anon(0, ps).expect("failed to add mapping");
1176 m.remove(0, ps - 1)
1177 .expect("failed to remove unaligned mapping");
1178 }
1179
1180 #[test]
1181 fn arena_msync() {
1182 let size = 0x40000;
1183 let m = MemoryMappingArena::new(size).unwrap();
1184 let ps = pagesize();
1185 <dyn MappedRegion>::msync(&m, 0, ps).unwrap();
1186 <dyn MappedRegion>::msync(&m, 0, size).unwrap();
1187 <dyn MappedRegion>::msync(&m, ps, size - ps).unwrap();
1188 let res = <dyn MappedRegion>::msync(&m, ps, size).unwrap_err();
1189 match res {
1190 Error::InvalidAddress => {}
1191 e => panic!("unexpected error: {e}"),
1192 }
1193 }
1194
1195 #[test]
1196 fn arena_madvise() {
1197 let size = 0x40000;
1198 let mut m = MemoryMappingArena::new(size).unwrap();
1199 m.add_anon_protection(0, size, Protection::read_write())
1200 .expect("failed to add writable protection for madvise MADV_REMOVE");
1201 let ps = pagesize();
1202 <dyn MappedRegion>::madvise(&m, 0, ps, libc::MADV_PAGEOUT).unwrap();
1203 <dyn MappedRegion>::madvise(&m, 0, size, libc::MADV_PAGEOUT).unwrap();
1204 <dyn MappedRegion>::madvise(&m, ps, size - ps, libc::MADV_REMOVE).unwrap();
1205 let res = <dyn MappedRegion>::madvise(&m, ps, size, libc::MADV_PAGEOUT).unwrap_err();
1206 match res {
1207 Error::InvalidAddress => {}
1208 e => panic!("unexpected error: {e}"),
1209 }
1210 }
1211}