Skip to content

Commit 477743d

Browse files
Merge #1306
1306: Add wrapper for mremap r=asomers a=sporksmith Fixes #1295 Co-authored-by: Jim Newsome <[email protected]>
2 parents c8e8def + 6f84f14 commit 477743d

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased] - ReleaseDate
77
### Added
8+
- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306))
89
### Changed
910
### Fixed
1011
### Removed

src/sys/mman.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,17 @@ libc_bitflags!{
139139
}
140140
}
141141

142+
#[cfg(target_os = "linux")]
143+
libc_bitflags!{
144+
/// Options for `mremap()`.
145+
pub struct MRemapFlags: c_int {
146+
/// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
147+
MREMAP_MAYMOVE;
148+
/// Place the mapping at exactly the address specified in `new_address`.
149+
MREMAP_FIXED;
150+
}
151+
}
152+
142153
libc_enum!{
143154
/// Usage information for a range of memory to allow for performance optimizations by the kernel.
144155
///
@@ -315,6 +326,30 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma
315326
}
316327
}
317328

329+
/// Expands (or shrinks) an existing memory mapping, potentially moving it at
330+
/// the same time.
331+
///
332+
/// # Safety
333+
///
334+
/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
335+
/// detailed requirements.
336+
#[cfg(target_os = "linux")]
337+
pub unsafe fn mremap(
338+
addr: *mut c_void,
339+
old_size: size_t,
340+
new_size: size_t,
341+
flags: MRemapFlags,
342+
new_address: Option<* mut c_void>,
343+
) -> Result<*mut c_void> {
344+
let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
345+
346+
if ret == libc::MAP_FAILED {
347+
Err(Error::Sys(Errno::last()))
348+
} else {
349+
Ok(ret)
350+
}
351+
}
352+
318353
/// remove a mapping
319354
///
320355
/// # Safety

test/sys/test_mman.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
use nix::Error;
2+
use nix::libc::{c_void, size_t};
3+
use nix::sys::mman::{mmap, MapFlags, ProtFlags};
4+
5+
#[cfg(target_os = "linux")]
6+
use nix::sys::mman::{mremap, MRemapFlags};
7+
8+
#[test]
9+
fn test_mmap_anonymous() {
10+
let ref mut byte = unsafe {
11+
let ptr = mmap(std::ptr::null_mut(), 1,
12+
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
13+
MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0)
14+
.unwrap();
15+
*(ptr as * mut u8)
16+
};
17+
assert_eq !(*byte, 0x00u8);
18+
*byte = 0xffu8;
19+
assert_eq !(*byte, 0xffu8);
20+
}
21+
22+
#[test]
23+
#[cfg(target_os = "linux")]
24+
fn test_mremap_grow() {
25+
const ONE_K : size_t = 1024;
26+
let slice : &mut[u8] = unsafe {
27+
let mem = mmap(std::ptr::null_mut(), ONE_K,
28+
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
29+
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
30+
.unwrap();
31+
std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
32+
};
33+
assert_eq !(slice[ONE_K - 1], 0x00);
34+
slice[ONE_K - 1] = 0xFF;
35+
assert_eq !(slice[ONE_K - 1], 0xFF);
36+
37+
let slice : &mut[u8] = unsafe {
38+
let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K,
39+
MRemapFlags::MREMAP_MAYMOVE, None)
40+
.unwrap();
41+
std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K)
42+
};
43+
44+
// The first KB should still have the old data in it.
45+
assert_eq !(slice[ONE_K - 1], 0xFF);
46+
47+
// The additional range should be zero-init'd and accessible.
48+
assert_eq !(slice[10 * ONE_K - 1], 0x00);
49+
slice[10 * ONE_K - 1] = 0xFF;
50+
assert_eq !(slice[10 * ONE_K - 1], 0xFF);
51+
}
52+
53+
#[test]
54+
#[cfg(target_os = "linux")]
55+
fn test_mremap_shrink() {
56+
const ONE_K : size_t = 1024;
57+
let slice : &mut[u8] = unsafe {
58+
let mem = mmap(std::ptr::null_mut(), 10 * ONE_K,
59+
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
60+
MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
61+
.unwrap();
62+
std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
63+
};
64+
assert_eq !(slice[ONE_K - 1], 0x00);
65+
slice[ONE_K - 1] = 0xFF;
66+
assert_eq !(slice[ONE_K - 1], 0xFF);
67+
68+
let slice : &mut[u8] = unsafe {
69+
let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K,
70+
MRemapFlags::empty(), None)
71+
.unwrap();
72+
// Since we didn't supply MREMAP_MAYMOVE, the address should be the
73+
// same.
74+
assert_eq !(mem, slice.as_mut_ptr() as * mut c_void);
75+
std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
76+
};
77+
78+
// The first KB should still be accessible and have the old data in it.
79+
assert_eq !(slice[ONE_K - 1], 0xFF);
80+
}

0 commit comments

Comments
 (0)