diff options
| author | Corey Richardson <corey@octayn.net> | 2014-01-18 17:50:49 -0500 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-01-24 22:30:01 -0800 |
| commit | bf5152f486a88ea106a820387d7d807ea99962af (patch) | |
| tree | 22774779486e84acd449da5fd0d8a669c64cdb31 /src | |
| parent | 7499e2dd4596893980aaed0ca0558eec89ce47ad (diff) | |
| download | rust-bf5152f486a88ea106a820387d7d807ea99962af.tar.gz rust-bf5152f486a88ea106a820387d7d807ea99962af.zip | |
Fix zero-sized memory mapping
Diffstat (limited to 'src')
| -rw-r--r-- | src/libgreen/coroutine.rs | 2 | ||||
| -rw-r--r-- | src/libgreen/stack.rs | 16 | ||||
| -rw-r--r-- | src/libstd/os.rs | 15 |
3 files changed, 28 insertions, 5 deletions
diff --git a/src/libgreen/coroutine.rs b/src/libgreen/coroutine.rs index 3d7dc58a1b2..c001d40a246 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 a5d5174b91b..84c1572ad35 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 b594b91d2dc..004031937b0 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<MemoryMap, MapError> { 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); |
