Implement the GuardedStack marker trait.

This commit is contained in:
whitequark 2016-07-17 03:45:50 +00:00 committed by edef
parent 7ffad26cfd
commit 16c674b4f4
4 changed files with 34 additions and 20 deletions

View File

@ -68,6 +68,16 @@ impl<Item, Stack> Generator<Item, Stack>
where Item: Send, Stack: stack::Stack { where Item: Send, Stack: stack::Stack {
/// Creates a new generator. /// Creates a new generator.
pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack> pub fn new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder<Item, Stack>) + Send {
unsafe { Generator::unsafe_new(stack, f) }
}
/// Same as `new`, but does not require `stack` to have a guard page.
///
/// This function is unsafe because the generator function can easily violate
/// memory safety by overflowing the stack. It is useful in environments where
/// guarded stacks do not exist, e.g. in absence of an MMU.
pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Item, Stack>
where F: FnOnce(&mut Yielder<Item, Stack>) + Send { where F: FnOnce(&mut Yielder<Item, Stack>) + Send {
unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> ! unsafe extern "C" fn generator_wrapper<Item, Stack, F>(info: usize) -> !
where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) { where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder<Item, Stack>) {
@ -82,7 +92,6 @@ impl<Item, Stack> Generator<Item, Stack>
loop { yielder.return_(None) } loop { yielder.return_(None) }
} }
unsafe {
let mut generator = Generator { let mut generator = Generator {
state: State::Suspended, state: State::Suspended,
context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>), context: context::Context::new(stack, generator_wrapper::<Item, Stack, F>),
@ -97,7 +106,6 @@ impl<Item, Stack> Generator<Item, Stack>
generator generator
} }
}
/// Returns the state of the generator. /// Returns the state of the generator.
pub fn state(&self) -> State { self.state } pub fn state(&self) -> State { self.state }

View File

@ -30,6 +30,7 @@
extern crate std; extern crate std;
pub use stack::Stack; pub use stack::Stack;
pub use stack::GuardedStack;
pub use context::Context; pub use context::Context;
pub use generator::Generator; pub use generator::Generator;

View File

@ -7,11 +7,8 @@ use stack;
mod sys; mod sys;
/// OsStack holds a stack allocated using the operating system's anonymous /// OsStack holds a guarded stack allocated using the operating system's anonymous
/// memory mapping facility. /// memory mapping facility.
///
/// The stack it provides comes with a guard page, which is not included
/// in the stack limit.
#[derive(Debug)] #[derive(Debug)]
pub struct Stack { pub struct Stack {
ptr: *mut u8, ptr: *mut u8,
@ -22,9 +19,9 @@ unsafe impl Send for Stack {}
impl Stack { impl Stack {
/// Allocates a new stack with at least `size` accessible bytes. /// Allocates a new stack with at least `size` accessible bytes.
/// `size` is rounded up to an integral number of pages; `Stack::new(0)` /// `size` is rounded up to an integral number of pages; `Stack::new(0)` is legal
/// is legal and allocates the smallest possible stack, consisting /// and allocates the smallest possible stack, consisting of one data page and
/// of one data page and one guard page. /// one guard page.
pub fn new(size: usize) -> Result<Stack, IoError> { pub fn new(size: usize) -> Result<Stack, IoError> {
let page_size = sys::page_size(); let page_size = sys::page_size();
@ -66,6 +63,8 @@ impl stack::Stack for Stack {
} }
} }
unsafe impl stack::GuardedStack for Stack {}
impl Drop for Stack { impl Drop for Stack {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { sys::unmap_stack(self.ptr, self.len) }.expect("cannot unmap stack") unsafe { sys::unmap_stack(self.ptr, self.len) }.expect("cannot unmap stack")

View File

@ -14,3 +14,9 @@ pub trait Stack {
/// so this is the lowest address. /// so this is the lowest address.
fn limit(&self) -> *mut u8; fn limit(&self) -> *mut u8;
} }
/// A marker trait for `Stack` objects with a guard page.
///
/// A guarded stack must guarantee that any access of data at addresses `limit()` to
/// `limit().offset(4096)` will abnormally terminate the program.
pub unsafe trait GuardedStack {}