Fix zero-sized memory mapping
This commit is contained in:
parent
7499e2dd45
commit
bf5152f486
3 changed files with 28 additions and 5 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue