mmap_rs_with_map_from_existing/
lib.rs1#![doc = include_str!("../README.md")]
2#![deny(
3 missing_docs,
4 rustdoc::broken_intra_doc_links,
5 missing_debug_implementations
6)]
7
8mod areas;
9pub mod error;
10mod mmap;
11mod os_impl;
12
13pub use areas::*;
14pub use error::Error;
15pub use mmap::*;
16
17#[cfg(test)]
18mod tests {
19 #[test]
20 fn reserve_none() {
21 use crate::{MemoryAreas, MmapNone, MmapOptions, Protection, ShareMode};
22
23 let mapping = MmapOptions::new(MmapOptions::page_size())
24 .unwrap()
25 .reserve_none()
26 .unwrap();
27
28 assert!(mapping.as_ptr() != std::ptr::null());
29
30 let mapping: MmapNone = mapping.try_into().unwrap();
31
32 assert!(mapping.as_ptr() != std::ptr::null());
33
34 let region = MemoryAreas::query(mapping.as_ptr() as usize)
35 .unwrap()
36 .unwrap();
37
38 assert_eq!(region.share_mode, ShareMode::Private);
39 assert!(!region.protection.contains(Protection::READ));
40 assert!(!region.protection.contains(Protection::WRITE));
41 assert!(!region.protection.contains(Protection::EXECUTE));
42 }
43
44 #[test]
45 fn reserve() {
46 use crate::{MemoryAreas, Mmap, MmapOptions, Protection, ShareMode};
47
48 let mapping = MmapOptions::new(MmapOptions::page_size())
49 .unwrap()
50 .map()
51 .unwrap();
52
53 assert!(mapping.as_ptr() != std::ptr::null());
54
55 let mapping: Mmap = mapping.try_into().unwrap();
56
57 assert!(mapping.as_ptr() != std::ptr::null());
58
59 let region = MemoryAreas::query(mapping.as_ptr() as usize)
60 .unwrap()
61 .unwrap();
62
63 assert_eq!(region.share_mode, ShareMode::Private);
64 assert!(region.protection.contains(Protection::READ));
65 assert!(!region.protection.contains(Protection::WRITE));
66 assert!(!region.protection.contains(Protection::EXECUTE));
67 }
68
69 #[test]
70 fn reserve_mut() {
71 use crate::{MemoryAreas, MmapMut, MmapOptions, Protection, ShareMode};
72
73 let mapping = MmapOptions::new(MmapOptions::page_size())
74 .unwrap()
75 .reserve_mut()
76 .unwrap();
77
78 assert!(mapping.as_ptr() != std::ptr::null());
79
80 let mut mapping: MmapMut = mapping.try_into().unwrap();
81
82 mapping[0] = 0x42;
83
84 assert!(mapping.as_ptr() != std::ptr::null());
85 assert_eq!(mapping[0], 0x42);
86
87 let region = MemoryAreas::query(mapping.as_ptr() as usize)
88 .unwrap()
89 .unwrap();
90
91 assert_eq!(region.share_mode, ShareMode::Private);
92 assert!(region.protection.contains(Protection::READ));
93 assert!(region.protection.contains(Protection::WRITE));
94 assert!(!region.protection.contains(Protection::EXECUTE));
95 }
96
97 #[test]
98 fn map_none() {
99 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
100
101 let mapping = MmapOptions::new(MmapOptions::page_size())
102 .unwrap()
103 .map_none()
104 .unwrap();
105
106 assert!(mapping.as_ptr() != std::ptr::null());
107
108 let region = MemoryAreas::query(mapping.as_ptr() as usize)
109 .unwrap()
110 .unwrap();
111
112 assert_eq!(region.share_mode, ShareMode::Private);
113 assert!(!region.protection.contains(Protection::READ));
114 assert!(!region.protection.contains(Protection::WRITE));
115 assert!(!region.protection.contains(Protection::EXECUTE));
116 }
117
118 #[test]
119 fn map() {
120 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
121
122 let mapping = MmapOptions::new(MmapOptions::page_size())
123 .unwrap()
124 .map()
125 .unwrap();
126
127 assert!(mapping.as_ptr() != std::ptr::null());
128
129 let region = MemoryAreas::query(mapping.as_ptr() as usize)
130 .unwrap()
131 .unwrap();
132
133 assert_eq!(region.share_mode, ShareMode::Private);
134 assert!(region.protection.contains(Protection::READ));
135 assert!(!region.protection.contains(Protection::WRITE));
136 assert!(!region.protection.contains(Protection::EXECUTE));
137 }
138
139 #[test]
140 fn map_existing() {
141 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
142
143 const PRETEND_CODE: u8 = 0xC3; let mut mapping = MmapOptions::new(MmapOptions::page_size())
147 .unwrap()
148 .map_mut()
149 .unwrap();
150
151 assert!(mapping.as_ptr() != std::ptr::null());
152
153 unsafe { *mapping.as_mut_ptr() = PRETEND_CODE };
155
156 let region = MemoryAreas::query(mapping.as_ptr() as usize)
158 .unwrap()
159 .unwrap();
160
161 assert_eq!(region.share_mode, ShareMode::Private);
162 assert!(region.protection.contains(Protection::READ));
163 assert!(region.protection.contains(Protection::WRITE));
164 assert!(!region.protection.contains(Protection::EXECUTE));
165
166 let remapped = unsafe {
168 MmapOptions::new(MmapOptions::page_size())
169 .unwrap()
170 .with_address(mapping.as_ptr() as usize)
171 .map_from_existing()
172 .unwrap()
173 };
174
175 unsafe { assert_eq!(PRETEND_CODE, *remapped.as_ptr()) };
177
178 let _unused = remapped.make_exec();
180
181 let region = MemoryAreas::query(mapping.as_ptr() as usize)
182 .unwrap()
183 .unwrap();
184
185 assert_eq!(region.share_mode, ShareMode::Private);
186 assert!(region.protection.contains(Protection::READ));
187 assert!(!region.protection.contains(Protection::WRITE)); assert!(region.protection.contains(Protection::EXECUTE));
189 }
190
191 #[test]
192 fn map_mut() {
193 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
194
195 let mut mapping = MmapOptions::new(MmapOptions::page_size())
196 .unwrap()
197 .map_mut()
198 .unwrap();
199
200 mapping[0] = 0x42;
201
202 assert!(mapping.as_ptr() != std::ptr::null());
203 assert_eq!(mapping[0], 0x42);
204
205 let region = MemoryAreas::query(mapping.as_ptr() as usize)
206 .unwrap()
207 .unwrap();
208
209 assert_eq!(region.share_mode, ShareMode::Private);
210 assert!(region.protection.contains(Protection::READ));
211 assert!(region.protection.contains(Protection::WRITE));
212 assert!(!region.protection.contains(Protection::EXECUTE));
213 }
214
215 #[test]
216 fn map_file() {
217 use crate::{MemoryAreas, MmapFlags, MmapOptions, Protection, ShareMode};
218 use std::io::Write;
219 use tempfile::NamedTempFile;
220
221 let mut file = NamedTempFile::new().unwrap();
222
223 let mut bytes = vec![0u8; MmapOptions::page_size()];
224 bytes[0] = 0x42;
225 file.as_file_mut().write(&bytes).unwrap();
226
227 let mapping = unsafe {
228 MmapOptions::new(MmapOptions::page_size())
229 .unwrap()
230 .with_flags(MmapFlags::SHARED)
231 .with_file(file.as_file(), 0)
232 .map()
233 .unwrap()
234 };
235
236 let other_mapping = unsafe {
237 MmapOptions::new(MmapOptions::page_size())
238 .unwrap()
239 .with_flags(MmapFlags::SHARED)
240 .with_file(file.as_file(), 0)
241 .map()
242 .unwrap()
243 };
244
245 assert_ne!(mapping.as_ptr(), std::ptr::null());
246 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
247 assert_eq!(mapping[0], 0x42);
248 assert_eq!(other_mapping[0], 0x42);
249
250 let region = MemoryAreas::query(mapping.as_ptr() as usize)
251 .unwrap()
252 .unwrap();
253
254 assert_eq!(region.share_mode, ShareMode::Shared);
255 assert!(region.protection.contains(Protection::READ));
256 assert!(!region.protection.contains(Protection::WRITE));
257 assert!(!region.protection.contains(Protection::EXECUTE));
258 #[cfg(not(target_os = "freebsd"))]
259 assert!(region.path().is_some());
260 }
261
262 #[test]
263 fn map_file_mut() {
264 use crate::{MemoryAreas, MmapFlags, MmapOptions, Protection, ShareMode};
265 use std::io::{Read, Seek, SeekFrom, Write};
266 use tempfile::NamedTempFile;
267
268 let mut file = NamedTempFile::new().unwrap();
269
270 let mut bytes = vec![0u8; MmapOptions::page_size()];
271 file.as_file_mut().write(&bytes).unwrap();
272
273 let mut mapping = unsafe {
274 MmapOptions::new(MmapOptions::page_size())
275 .unwrap()
276 .with_flags(MmapFlags::SHARED)
277 .with_file(file.as_file(), 0)
278 .map_mut()
279 .unwrap()
280 };
281
282 let other_mapping = unsafe {
283 MmapOptions::new(MmapOptions::page_size())
284 .unwrap()
285 .with_flags(MmapFlags::SHARED)
286 .with_file(file.as_file(), 0)
287 .map()
288 .unwrap()
289 };
290
291 assert_ne!(mapping.as_ptr(), std::ptr::null());
292 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
293 mapping[0] = 0x42;
294 assert_eq!(other_mapping[0], 0x42);
295 mapping.flush(0..MmapOptions::page_size()).unwrap();
296 file.as_file_mut().sync_all().unwrap();
297
298 let region = MemoryAreas::query(mapping.as_ptr() as usize)
299 .unwrap()
300 .unwrap();
301
302 assert_eq!(region.share_mode, ShareMode::Shared);
303 assert!(region.protection.contains(Protection::READ));
304 assert!(region.protection.contains(Protection::WRITE));
305 assert!(!region.protection.contains(Protection::EXECUTE));
306 #[cfg(not(target_os = "freebsd"))]
307 assert!(region.path().is_some());
308
309 file.as_file_mut().seek(SeekFrom::Start(0)).unwrap();
310 file.as_file().read(&mut bytes).unwrap();
311 assert_eq!(bytes[0], 0x42);
312 }
313
314 #[test]
315 fn map_file_private() {
316 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
317 use std::io::{Read, Seek, SeekFrom, Write};
318 use tempfile::NamedTempFile;
319
320 let mut file = NamedTempFile::new().unwrap();
321
322 let mut bytes = vec![0u8; MmapOptions::page_size()];
323 file.as_file_mut().write(&bytes).unwrap();
324
325 let mut mapping = unsafe {
326 MmapOptions::new(MmapOptions::page_size())
327 .unwrap()
328 .with_file(file.as_file(), 0)
329 .map_mut()
330 .unwrap()
331 };
332
333 let other_mapping = unsafe {
334 MmapOptions::new(MmapOptions::page_size())
335 .unwrap()
336 .with_file(file.as_file(), 0)
337 .map()
338 .unwrap()
339 };
340
341 assert_ne!(mapping.as_ptr(), std::ptr::null());
342 assert_ne!(other_mapping.as_ptr(), std::ptr::null());
343 mapping[0] = 0x42;
344 assert_ne!(other_mapping[0], 0x42);
345 mapping.flush(0..MmapOptions::page_size()).unwrap();
346 file.as_file_mut().sync_all().unwrap();
347
348 let region = MemoryAreas::query(mapping.as_ptr() as usize)
349 .unwrap()
350 .unwrap();
351
352 assert_eq!(region.share_mode, ShareMode::Private);
353 assert!(region.protection.contains(Protection::READ));
354 assert!(region.protection.contains(Protection::WRITE));
355 assert!(!region.protection.contains(Protection::EXECUTE));
356 #[cfg(not(target_os = "freebsd"))]
357 assert!(region.path().is_some());
358
359 file.as_file_mut().seek(SeekFrom::Start(0)).unwrap();
360 file.as_file().read(&mut bytes).unwrap();
361 assert_ne!(bytes[0], 0x42);
362 }
363
364 #[test]
365 fn reserve_and_split() {
366 use crate::{MmapMut, MmapOptions};
367
368 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
369 .unwrap()
370 .reserve_mut()
371 .unwrap();
372
373 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
374
375 assert!(mapping.as_ptr() < rest.as_ptr());
376
377 let mut rest: MmapMut = rest.try_into().unwrap();
378
379 rest[0] = 0x42;
380 assert_eq!(rest[0], 0x42);
381
382 assert_eq!(mapping.len(), MmapOptions::page_size());
383 assert_eq!(rest.len(), MmapOptions::page_size());
384 assert!(mapping.as_ptr() < rest.as_ptr());
385 }
386
387 #[test]
388 fn split_off() {
389 use crate::MmapOptions;
390
391 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
392 .unwrap()
393 .map_mut()
394 .unwrap();
395
396 assert!(mapping.split_off(1).is_err());
397
398 mapping[0] = 0x1;
399 mapping[MmapOptions::page_size()] = 0x2;
400
401 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
402
403 assert_eq!(mapping[0], 0x1);
404 assert_eq!(rest[0], 0x2);
405 assert_eq!(mapping.len(), MmapOptions::page_size());
406 assert_eq!(rest.len(), MmapOptions::page_size());
407 assert!(mapping.as_ptr() < rest.as_ptr());
408 }
409
410 #[test]
411 fn split_to() {
412 use crate::MmapOptions;
413
414 let mut mapping = MmapOptions::new(2 * MmapOptions::page_size())
415 .unwrap()
416 .map_mut()
417 .unwrap();
418
419 assert!(mapping.split_to(1).is_err());
420
421 mapping[0] = 0x1;
422 mapping[MmapOptions::page_size()] = 0x2;
423
424 let rest = mapping.split_to(MmapOptions::page_size()).unwrap();
425
426 assert_eq!(mapping[0], 0x2);
427 assert_eq!(rest[0], 0x1);
428 assert_eq!(mapping.len(), MmapOptions::page_size());
429 assert_eq!(rest.len(), MmapOptions::page_size());
430 assert!(mapping.as_ptr() > rest.as_ptr());
431 }
432
433 #[test]
434 fn split_file() {
435 use crate::MmapOptions;
436 use std::io::Write;
437 use tempfile::NamedTempFile;
438
439 let mut file = NamedTempFile::new().unwrap();
440
441 let mut bytes = vec![0u8; 2 * MmapOptions::page_size()];
442 bytes[0] = 0x1;
443 bytes[MmapOptions::page_size()] = 0x2;
444 file.as_file_mut().write(&bytes).unwrap();
445
446 let mut mapping = unsafe {
447 MmapOptions::new(2 * MmapOptions::page_size())
448 .unwrap()
449 .with_file(file.as_file(), 0)
450 .map()
451 .unwrap()
452 };
453
454 assert!(mapping.split_off(1).is_err());
455
456 let rest = mapping.split_off(MmapOptions::page_size()).unwrap();
457
458 assert_eq!(mapping[0], 0x1);
459 assert_eq!(rest[0], 0x2);
460 assert_eq!(mapping.len(), MmapOptions::page_size());
461 assert_eq!(rest.len(), MmapOptions::page_size());
462 assert!(mapping.as_ptr() < rest.as_ptr());
463 }
464
465 #[test]
466 fn split_and_merge() {
467 use crate::{MemoryAreas, MmapOptions, Protection, ShareMode};
468
469 let mut left = MmapOptions::new(3 * MmapOptions::page_size())
471 .unwrap()
472 .map_mut()
473 .unwrap();
474
475 let mut middle = left.split_off(MmapOptions::page_size()).unwrap();
477 let right = middle.split_off(MmapOptions::page_size()).unwrap();
478
479 assert!(left.as_ptr() < middle.as_ptr());
480 assert!(middle.as_ptr() < right.as_ptr());
481
482 let Err((_, mut right)) = left.merge(right) else { panic!("expected merge to fail") };
484 let Err((_, left)) = right.merge(left) else { panic!("expected merge to fail") };
485
486 let Err((_, mut left)) = middle.merge(left) else { panic!("expected merge to fail") };
488 left.merge(middle).unwrap();
489
490 let Err((_, mut left)) = right.merge(left) else { panic!("expected merge to fail") };
492 left.merge(right).unwrap();
493
494 assert_eq!(left.size(), 3 * MmapOptions::page_size());
496
497 let region = MemoryAreas::query(left.as_ptr() as usize).unwrap().unwrap();
498
499 assert_eq!(region.share_mode, ShareMode::Private);
500 assert!(region.protection.contains(Protection::READ));
501 assert!(region.protection.contains(Protection::WRITE));
502 assert!(!region.protection.contains(Protection::EXECUTE));
503
504 assert!(region.range.start <= left.start());
506
507 let padding = left.start().saturating_sub(region.range.start);
509 let size = region.range.len().saturating_sub(padding);
510
511 assert!(size >= 3 * MmapOptions::page_size());
513 }
514
515 #[test]
516 fn query_range() {
517 use crate::{MemoryAreas, MmapOptions};
518
519 let mut left = MmapOptions::new(3 * MmapOptions::page_size())
521 .unwrap()
522 .map_mut()
523 .unwrap();
524
525 let mut middle = left.split_off(MmapOptions::page_size()).unwrap();
527 let right = middle.split_off(MmapOptions::page_size()).unwrap();
528
529 assert!(left.as_ptr() < middle.as_ptr());
530 assert!(middle.as_ptr() < right.as_ptr());
531
532 drop(middle);
534
535 let start = left.as_ptr() as usize;
537 let end = right.as_ptr() as usize + right.len();
538
539 let mut areas = MemoryAreas::query_range(start..end).unwrap();
540
541 let region = areas.next().unwrap().unwrap();
542 assert_eq!(
543 region.end(),
544 left.as_ptr() as usize + MmapOptions::page_size()
545 );
546 let mut region = areas.next().unwrap().unwrap();
547
548 if region.start() != right.as_ptr() as usize {
549 region = areas.next().unwrap().unwrap();
550 }
551
552 assert_eq!(region.start(), right.as_ptr() as usize);
553 assert!(areas.next().is_none());
554 }
555}