Skip to content

Commit a6f1dba

Browse files
committed
Implement the mmap64 foreign item.
`mmap64` is like `mmap` but uses a 64-bit integer instead of `off_t` for the offset parameter.
1 parent 71f8f49 commit a6f1dba

File tree

3 files changed

+122
-2
lines changed

3 files changed

+122
-2
lines changed

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
262262

263263
"mmap" => {
264264
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
265+
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
265266
let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
266267
this.write_scalar(ptr, dest)?;
267268
}
269+
"mmap64" => {
270+
let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
271+
let offset = this.read_scalar(offset)?.to_i64()?;
272+
let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
273+
this.write_scalar(ptr, dest)?;
274+
}
268275
"munmap" => {
269276
let [addr, length] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
270277
let result = this.munmap(addr, length)?;

src/tools/miri/src/shims/unix/mem.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
2626
prot: &OpTy<'tcx, Provenance>,
2727
flags: &OpTy<'tcx, Provenance>,
2828
fd: &OpTy<'tcx, Provenance>,
29-
offset: &OpTy<'tcx, Provenance>,
29+
offset: i128,
3030
) -> InterpResult<'tcx, Scalar<Provenance>> {
3131
let this = self.eval_context_mut();
3232

@@ -36,7 +36,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3636
let prot = this.read_scalar(prot)?.to_i32()?;
3737
let flags = this.read_scalar(flags)?.to_i32()?;
3838
let fd = this.read_scalar(fd)?.to_i32()?;
39-
let offset = this.read_target_usize(offset)?;
4039

4140
let map_private = this.eval_libc_i32("MAP_PRIVATE");
4241
let map_anonymous = this.eval_libc_i32("MAP_ANONYMOUS");

src/tools/miri/tests/pass-dep/shims/mmap.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,118 @@ fn test_mmap() {
116116
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
117117
}
118118

119+
#[cfg(target_os = "linux")]
120+
fn test_mmap64() {
121+
let page_size = page_size::get();
122+
let ptr = unsafe {
123+
libc::mmap64(
124+
ptr::null_mut(),
125+
page_size,
126+
libc::PROT_READ | libc::PROT_WRITE,
127+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
128+
-1,
129+
0,
130+
)
131+
};
132+
assert!(!ptr.is_null());
133+
134+
// Ensure that freshly mapped allocations are zeroed
135+
let slice = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, page_size) };
136+
assert!(slice.iter().all(|b| *b == 0));
137+
138+
// Do some writes, make sure they worked
139+
for b in slice.iter_mut() {
140+
*b = 1;
141+
}
142+
assert!(slice.iter().all(|b| *b == 1));
143+
144+
// Ensure that we can munmap
145+
let res = unsafe { libc::munmap(ptr, page_size) };
146+
assert_eq!(res, 0i32);
147+
148+
// Test all of our error conditions
149+
let ptr = unsafe {
150+
libc::mmap64(
151+
ptr::null_mut(),
152+
page_size,
153+
libc::PROT_READ | libc::PROT_WRITE,
154+
libc::MAP_PRIVATE | libc::MAP_SHARED, // Can't be both private and shared
155+
-1,
156+
0,
157+
)
158+
};
159+
assert_eq!(ptr, libc::MAP_FAILED);
160+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
161+
162+
let ptr = unsafe {
163+
libc::mmap64(
164+
ptr::null_mut(),
165+
0, // Can't map no memory
166+
libc::PROT_READ | libc::PROT_WRITE,
167+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
168+
-1,
169+
0,
170+
)
171+
};
172+
assert_eq!(ptr, libc::MAP_FAILED);
173+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
174+
175+
let ptr = unsafe {
176+
libc::mmap64(
177+
ptr::invalid_mut(page_size * 64),
178+
page_size,
179+
libc::PROT_READ | libc::PROT_WRITE,
180+
// We don't support MAP_FIXED
181+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED,
182+
-1,
183+
0,
184+
)
185+
};
186+
assert_eq!(ptr, libc::MAP_FAILED);
187+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
188+
189+
// We don't support protections other than read+write
190+
for prot in [libc::PROT_NONE, libc::PROT_EXEC, libc::PROT_READ, libc::PROT_WRITE] {
191+
let ptr = unsafe {
192+
libc::mmap64(
193+
ptr::null_mut(),
194+
page_size,
195+
prot,
196+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
197+
-1,
198+
0,
199+
)
200+
};
201+
assert_eq!(ptr, libc::MAP_FAILED);
202+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
203+
}
204+
205+
// We report an error for mappings whose length cannot be rounded up to a multiple of
206+
// the page size.
207+
let ptr = unsafe {
208+
libc::mmap64(
209+
ptr::null_mut(),
210+
usize::MAX - 1,
211+
libc::PROT_READ | libc::PROT_WRITE,
212+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
213+
-1,
214+
0,
215+
)
216+
};
217+
assert_eq!(ptr, libc::MAP_FAILED);
218+
219+
// We report an error when trying to munmap an address which is not a multiple of the page size
220+
let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
221+
assert_eq!(res, -1);
222+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
223+
224+
// We report an error when trying to munmap a length that cannot be rounded up to a multiple of
225+
// the page size.
226+
let res = unsafe { libc::munmap(ptr::invalid_mut(page_size), usize::MAX - 1) };
227+
assert_eq!(res, -1);
228+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
229+
}
230+
119231
#[cfg(target_os = "linux")]
120232
fn test_mremap() {
121233
let page_size = page_size::get();
@@ -165,5 +277,7 @@ fn test_mremap() {
165277
fn main() {
166278
test_mmap();
167279
#[cfg(target_os = "linux")]
280+
test_mmap64();
281+
#[cfg(target_os = "linux")]
168282
test_mremap();
169283
}

0 commit comments

Comments
 (0)