diff --git a/src/libgreen/coroutine.rs b/src/libgreen/coroutine.rs index 3d7dc58a1b24..c001d40a2465 100644 --- a/src/libgreen/coroutine.rs +++ b/src/libgreen/coroutine.rs @@ -49,7 +49,7 @@ impl Coroutine { pub fn empty() -> Coroutine { Coroutine { - current_stack_segment: Stack::new(0), + current_stack_segment: unsafe { Stack::dummy_stack() }, saved_context: Context::empty() } } diff --git a/src/libgreen/stack.rs b/src/libgreen/stack.rs index a5d5174b91b9..84c1572ad353 100644 --- a/src/libgreen/stack.rs +++ b/src/libgreen/stack.rs @@ -9,7 +9,8 @@ // except according to those terms. use std::rt::env::max_cached_stacks; -use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable, MapNonStandardFlags}; +use std::os::{errno, page_size, MemoryMap, MapReadable, MapWritable, + MapNonStandardFlags, MapVirtual}; #[cfg(not(windows))] use std::libc::{MAP_STACK, MAP_PRIVATE, MAP_ANON}; use std::libc::{c_uint, c_int, c_void, uintptr_t}; @@ -33,6 +34,8 @@ static STACK_FLAGS: c_int = MAP_PRIVATE | MAP_ANON; static STACK_FLAGS: c_int = 0; impl Stack { + /// Allocate a new stack of `size`. If size = 0, this will fail. Use + /// `dummy_stack` if you want a zero-sized stack. pub fn new(size: uint) -> Stack { // Map in a stack. Eventually we might be able to handle stack allocation failure, which // would fail to spawn the task. But there's not many sensible things to do on OOM. @@ -62,12 +65,21 @@ impl Stack { return stk; } + /// Create a 0-length stack which starts (and ends) at 0. + pub unsafe fn dummy_stack() -> Stack { + Stack { + buf: MemoryMap { data: 0 as *mut u8, len: 0, kind: MapVirtual }, + min_size: 0, + valgrind_id: 0 + } + } + /// Point to the low end of the allocated stack pub fn start(&self) -> *uint { self.buf.data as *uint } - /// Point one word beyond the high end of the allocated stack + /// Point one uint beyond the high end of the allocated stack pub fn end(&self) -> *uint { unsafe { self.buf.data.offset(self.buf.len as int) as *uint diff --git a/src/libstd/os.rs b/src/libstd/os.rs index b594b91d2dca..004031937b0d 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -891,6 +891,10 @@ pub enum MapError { /// If using `MapAddr`, the address + `min_len` was outside of the process's address space. If /// using `MapFd`, the target of the fd didn't have enough resources to fulfill the request. ErrNoMem, + /// A zero-length map was requested. This is invalid according to + /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html). Not all + /// platforms obey this, but this wrapper does. + ErrZeroLength, /// Unrecognized error. The inner value is the unrecognized errno. ErrUnknown(int), /// ## The following are win32-specific @@ -922,6 +926,7 @@ impl fmt::Default for MapError { ErrUnsupProt => "Protection mode unsupported", ErrUnsupOffset => "Offset in virtual memory mode is unsupported", ErrAlreadyExists => "File mapping for specified file already exists", + ErrZeroLength => "Zero-length mapping not allowed", ErrUnknown(code) => { write!(out.buf, "Unknown error = {}", code); return }, ErrVirtualAlloc(code) => { write!(out.buf, "VirtualAlloc failure = {}", code); return }, ErrCreateFileMappingW(code) => { @@ -939,10 +944,14 @@ impl fmt::Default for MapError { #[cfg(unix)] impl MemoryMap { - /// Create a new mapping with the given `options`, at least `min_len` bytes long. + /// Create a new mapping with the given `options`, at least `min_len` bytes long. `min_len` + /// must be greater than zero; see the note on `ErrZeroLength`. pub fn new(min_len: uint, options: &[MapOption]) -> Result { use libc::off_t; + if min_len == 0 { + return Err(ErrZeroLength) + } let mut addr: *u8 = ptr::null(); let mut prot = 0; let mut flags = libc::MAP_PRIVATE; @@ -1005,6 +1014,8 @@ impl MemoryMap { impl Drop for MemoryMap { /// Unmap the mapping. Fails the task if `munmap` fails. fn drop(&mut self) { + if self.len == 0 { /* workaround for dummy_stack */ return; } + unsafe { match libc::munmap(self.data as *c_void, self.len as libc::size_t) { 0 => (), @@ -1442,7 +1453,7 @@ mod tests { os::MapWritable ]) { Ok(chunk) => chunk, - Err(msg) => fail!(msg.to_str()) + Err(msg) => fail!("{}", msg) }; assert!(chunk.len >= 16);