Skip to content

Commit 02d5495

Browse files
committed
Auto merge of #3219 - saethlin:map-failed, r=RalfJung
Return MAP_FAILED when mmap fails I don't properly remember why we ended up with a hodgepodge of return values, but #3218 correctly points out that we are supposed to return `MAP_FAILED`. This should fix that return value and also add sufficient tests to prevent making a similar mistake.
2 parents 0575ab0 + 22fd2a6 commit 02d5495

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

src/shims/unix/linux/mem.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
3838
if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
3939
// We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
4040
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
41-
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
41+
return Ok(this.eval_libc("MAP_FAILED"));
4242
}
4343

4444
let old_address = Machine::ptr_from_addr_cast(this, old_address)?;

src/shims/unix/mem.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4848
// First, we do some basic argument validation as required by mmap
4949
if (flags & (map_private | map_shared)).count_ones() != 1 {
5050
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
51-
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
51+
return Ok(this.eval_libc("MAP_FAILED"));
5252
}
5353
if length == 0 {
5454
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("EINVAL")))?;
55-
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
55+
return Ok(this.eval_libc("MAP_FAILED"));
5656
}
5757

5858
// If a user tries to map a file, we want to loudly inform them that this is not going
@@ -72,7 +72,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7272
// Miri doesn't support MAP_FIXED or any any protections other than PROT_READ|PROT_WRITE.
7373
if flags & map_fixed != 0 || prot != prot_read | prot_write {
7474
this.set_last_error(Scalar::from_i32(this.eval_libc_i32("ENOTSUP")))?;
75-
return Ok(Scalar::from_maybe_pointer(Pointer::null(), this));
75+
return Ok(this.eval_libc("MAP_FAILED"));
7676
}
7777

7878
// Miri does not support shared mappings, or any of the other extensions that for example

tests/pass-dep/shims/mmap.rs

+79
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
33
#![feature(strict_provenance)]
44

5+
use std::io::Error;
56
use std::{ptr, slice};
67

78
fn test_mmap() {
@@ -32,6 +33,67 @@ fn test_mmap() {
3233
let just_an_address = ptr::invalid_mut(ptr.addr());
3334
let res = unsafe { libc::munmap(just_an_address, page_size) };
3435
assert_eq!(res, 0i32);
36+
37+
// Test all of our error conditions
38+
let ptr = unsafe {
39+
libc::mmap(
40+
ptr::null_mut(),
41+
page_size,
42+
libc::PROT_READ | libc::PROT_WRITE,
43+
libc::MAP_PRIVATE | libc::MAP_SHARED, // Can't be both private and shared
44+
-1,
45+
0,
46+
)
47+
};
48+
assert_eq!(ptr, libc::MAP_FAILED);
49+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
50+
51+
let ptr = unsafe {
52+
libc::mmap(
53+
ptr::null_mut(),
54+
0, // Can't map no memory
55+
libc::PROT_READ | libc::PROT_WRITE,
56+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
57+
-1,
58+
0,
59+
)
60+
};
61+
assert_eq!(ptr, libc::MAP_FAILED);
62+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
63+
64+
let ptr = unsafe {
65+
libc::mmap(
66+
ptr::invalid_mut(page_size * 64),
67+
page_size,
68+
libc::PROT_READ | libc::PROT_WRITE,
69+
// We don't support MAP_FIXED
70+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED,
71+
-1,
72+
0,
73+
)
74+
};
75+
assert_eq!(ptr, libc::MAP_FAILED);
76+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
77+
78+
// We don't support protections other than read+write
79+
for prot in [libc::PROT_NONE, libc::PROT_EXEC, libc::PROT_READ, libc::PROT_WRITE] {
80+
let ptr = unsafe {
81+
libc::mmap(
82+
ptr::null_mut(),
83+
page_size,
84+
prot,
85+
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
86+
-1,
87+
0,
88+
)
89+
};
90+
assert_eq!(ptr, libc::MAP_FAILED);
91+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
92+
}
93+
94+
let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
95+
assert_eq!(res, -1);
96+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
3597
}
3698

3799
#[cfg(target_os = "linux")]
@@ -61,6 +123,23 @@ fn test_mremap() {
61123

62124
let res = unsafe { libc::munmap(ptr, page_size * 2) };
63125
assert_eq!(res, 0i32);
126+
127+
// Test all of our error conditions
128+
// Not aligned
129+
let ptr =
130+
unsafe { libc::mremap(ptr::invalid_mut(1), page_size, page_size, libc::MREMAP_MAYMOVE) };
131+
assert_eq!(ptr, libc::MAP_FAILED);
132+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
133+
134+
// Zero size
135+
let ptr = unsafe { libc::mremap(ptr::null_mut(), page_size, 0, libc::MREMAP_MAYMOVE) };
136+
assert_eq!(ptr, libc::MAP_FAILED);
137+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
138+
139+
// Not setting MREMAP_MAYMOVE
140+
let ptr = unsafe { libc::mremap(ptr::null_mut(), page_size, page_size, 0) };
141+
assert_eq!(ptr, libc::MAP_FAILED);
142+
assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
64143
}
65144

66145
fn main() {

0 commit comments

Comments
 (0)