Skip to content

Commit bf5152f

Browse files
emberianalexcrichton
authored andcommitted
Fix zero-sized memory mapping
1 parent 7499e2d commit bf5152f

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

src/libgreen/coroutine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Coroutine {
4949

5050
pub fn empty() -> Coroutine {
5151
Coroutine {
52-
current_stack_segment: Stack::new(0),
52+
current_stack_segment: unsafe { Stack::dummy_stack() },
5353
saved_context: Context::empty()
5454
}
5555
}

src/libgreen/stack.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
// except according to those terms.
1010

1111
use std::rt::env::max_cached_stacks;
12-
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable, MapNonStandardFlags};
12+
use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable,
13+
MapNonStandardFlags, MapVirtual};
1314
#[cfg(not(windows))]
1415
use std::libc::{MAP_STACK, MAP_PRIVATE, MAP_ANON};
1516
use std::libc::{c_uint, c_int, c_void, uintptr_t};
@@ -33,6 +34,8 @@ static STACK_FLAGS: c_int = MAP_PRIVATE | MAP_ANON;
3334
static STACK_FLAGS: c_int = 0;
3435

3536
impl Stack {
37+
/// Allocate a new stack of `size`. If size = 0, this will fail. Use
38+
/// `dummy_stack` if you want a zero-sized stack.
3639
pub fn new(size: uint) -> Stack {
3740
// Map in a stack. Eventually we might be able to handle stack allocation failure, which
3841
// would fail to spawn the task. But there's not many sensible things to do on OOM.
@@ -62,12 +65,21 @@ impl Stack {
6265
return stk;
6366
}
6467

68+
/// Create a 0-length stack which starts (and ends) at 0.
69+
pub unsafe fn dummy_stack() -> Stack {
70+
Stack {
71+
buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual },
72+
min_size: 0,
73+
valgrind_id: 0
74+
}
75+
}
76+
6577
/// Point to the low end of the allocated stack
6678
pub fn start(&self) -> *uint {
6779
self.buf.data as *uint
6880
}
6981

70-
/// Point one word beyond the high end of the allocated stack
82+
/// Point one uint beyond the high end of the allocated stack
7183
pub fn end(&self) -> *uint {
7284
unsafe {
7385
self.buf.data.offset(self.buf.len as int) as *uint

src/libstd/os.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,10 @@ pub enum MapError {
891891
/// If using `MapAddr`, the address + `min_len` was outside of the process's address space. If
892892
/// using `MapFd`, the target of the fd didn't have enough resources to fulfill the request.
893893
ErrNoMem,
894+
/// A zero-length map was requested. This is invalid according to
895+
/// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html). Not all
896+
/// platforms obey this, but this wrapper does.
897+
ErrZeroLength,
894898
/// Unrecognized error. The inner value is the unrecognized errno.
895899
ErrUnknown(int),
896900
/// ## The following are win32-specific
@@ -922,6 +926,7 @@ impl fmt::Default for MapError {
922926
ErrUnsupProt => "Protection mode unsupported",
923927
ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
924928
ErrAlreadyExists => "File mapping for specified file already exists",
929+
ErrZeroLength => "Zero-length mapping not allowed",
925930
ErrUnknown(code) => { write!(out.buf, "Unknown error = {}", code); return },
926931
ErrVirtualAlloc(code) => { write!(out.buf, "VirtualAlloc failure = {}", code); return },
927932
ErrCreateFileMappingW(code) => {
@@ -939,10 +944,14 @@ impl fmt::Default for MapError {
939944

940945
#[cfg(unix)]
941946
impl MemoryMap {
942-
/// Create a new mapping with the given `options`, at least `min_len` bytes long.
947+
/// Create a new mapping with the given `options`, at least `min_len` bytes long. `min_len`
948+
/// must be greater than zero; see the note on `ErrZeroLength`.
943949
pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
944950
use libc::off_t;
945951

952+
if min_len == 0 {
953+
return Err(ErrZeroLength)
954+
}
946955
let mut addr: *u8 = ptr::null();
947956
let mut prot = 0;
948957
let mut flags = libc::MAP_PRIVATE;
@@ -1005,6 +1014,8 @@ impl MemoryMap {
10051014
impl Drop for MemoryMap {
10061015
/// Unmap the mapping. Fails the task if `munmap` fails.
10071016
fn drop(&mut self) {
1017+
if self.len == 0 { /* workaround for dummy_stack */ return; }
1018+
10081019
unsafe {
10091020
match libc::munmap(self.data as *c_void, self.len as libc::size_t) {
10101021
0 => (),
@@ -1442,7 +1453,7 @@ mod tests {
14421453
os::MapWritable
14431454
]) {
14441455
Ok(chunk) => chunk,
1445-
Err(msg) => fail!(msg.to_str())
1456+
Err(msg) => fail!("{}", msg)
14461457
};
14471458
assert!(chunk.len >= 16);
14481459

0 commit comments

Comments
 (0)