Implement the mmap64 foreign item.
`mmap64` is like `mmap` but uses a 64-bit integer instead of `off_t` for the offset parameter.
This commit is contained in:
parent
71f8f4949e
commit
a6f1dbac79
3 changed files with 122 additions and 2 deletions
|
|
@ -262,9 +262,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
"mmap" => {
|
||||
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
|
||||
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
|
||||
let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
|
||||
this.write_scalar(ptr, dest)?;
|
||||
}
|
||||
"mmap64" => {
|
||||
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
|
||||
let offset = this.read_scalar(offset)?.to_i64()?;
|
||||
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
|
||||
this.write_scalar(ptr, dest)?;
|
||||
}
|
||||
"munmap" => {
|
||||
let [addr, length] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
|
||||
let result = this.munmap(addr, length)?;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
prot: &OpTy<'tcx, Provenance>,
|
||||
flags: &OpTy<'tcx, Provenance>,
|
||||
fd: &OpTy<'tcx, Provenance>,
|
||||
offset: &OpTy<'tcx, Provenance>,
|
||||
offset: i128,
|
||||
) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
|
|
@ -36,7 +36,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let prot = this.read_scalar(prot)?.to_i32()?;
|
||||
let flags = this.read_scalar(flags)?.to_i32()?;
|
||||
let fd = this.read_scalar(fd)?.to_i32()?;
|
||||
let offset = this.read_target_usize(offset)?;
|
||||
|
||||
let map_private = this.eval_libc_i32("MAP_PRIVATE");
|
||||
let map_anonymous = this.eval_libc_i32("MAP_ANONYMOUS");
|
||||
|
|
|
|||
|
|
@ -116,6 +116,118 @@ fn test_mmap() {
|
|||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_mmap64() {
|
||||
let page_size = page_size::get();
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::null_mut(),
|
||||
page_size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
// Ensure that freshly mapped allocations are zeroed
|
||||
let slice = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, page_size) };
|
||||
assert!(slice.iter().all(|b| *b == 0));
|
||||
|
||||
// Do some writes, make sure they worked
|
||||
for b in slice.iter_mut() {
|
||||
*b = 1;
|
||||
}
|
||||
assert!(slice.iter().all(|b| *b == 1));
|
||||
|
||||
// Ensure that we can munmap
|
||||
let res = unsafe { libc::munmap(ptr, page_size) };
|
||||
assert_eq!(res, 0i32);
|
||||
|
||||
// Test all of our error conditions
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::null_mut(),
|
||||
page_size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_PRIVATE | libc::MAP_SHARED, // Can't be both private and shared
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(ptr, libc::MAP_FAILED);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
|
||||
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::null_mut(),
|
||||
0, // Can't map no memory
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(ptr, libc::MAP_FAILED);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
|
||||
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::invalid_mut(page_size * 64),
|
||||
page_size,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
// We don't support MAP_FIXED
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(ptr, libc::MAP_FAILED);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
|
||||
|
||||
// We don't support protections other than read+write
|
||||
for prot in [libc::PROT_NONE, libc::PROT_EXEC, libc::PROT_READ, libc::PROT_WRITE] {
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::null_mut(),
|
||||
page_size,
|
||||
prot,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(ptr, libc::MAP_FAILED);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
|
||||
}
|
||||
|
||||
// We report an error for mappings whose length cannot be rounded up to a multiple of
|
||||
// the page size.
|
||||
let ptr = unsafe {
|
||||
libc::mmap64(
|
||||
ptr::null_mut(),
|
||||
usize::MAX - 1,
|
||||
libc::PROT_READ | libc::PROT_WRITE,
|
||||
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
assert_eq!(ptr, libc::MAP_FAILED);
|
||||
|
||||
// We report an error when trying to munmap an address which is not a multiple of the page size
|
||||
let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
|
||||
assert_eq!(res, -1);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
|
||||
|
||||
// We report an error when trying to munmap a length that cannot be rounded up to a multiple of
|
||||
// the page size.
|
||||
let res = unsafe { libc::munmap(ptr::invalid_mut(page_size), usize::MAX - 1) };
|
||||
assert_eq!(res, -1);
|
||||
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn test_mremap() {
|
||||
let page_size = page_size::get();
|
||||
|
|
@ -165,5 +277,7 @@ fn test_mremap() {
|
|||
fn main() {
|
||||
test_mmap();
|
||||
#[cfg(target_os = "linux")]
|
||||
test_mmap64();
|
||||
#[cfg(target_os = "linux")]
|
||||
test_mremap();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue