about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorCorey Richardson <corey@octayn.net>2014-01-18 17:50:49 -0500
committerAlex Crichton <alex@alexcrichton.com>2014-01-24 22:30:01 -0800
commitbf5152f486a88ea106a820387d7d807ea99962af (patch)
tree22774779486e84acd449da5fd0d8a669c64cdb31 /src
parent7499e2dd4596893980aaed0ca0558eec89ce47ad (diff)
downloadrust-bf5152f486a88ea106a820387d7d807ea99962af.tar.gz
rust-bf5152f486a88ea106a820387d7d807ea99962af.zip
Fix zero-sized memory mapping
Diffstat (limited to 'src')
-rw-r--r--src/libgreen/coroutine.rs2
-rw-r--r--src/libgreen/stack.rs16
-rw-r--r--src/libstd/os.rs15
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);