From 16c674b4f4623eea935be9354ba07527128f9d08 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 17 Jul 2016 03:45:50 +0000 Subject: [PATCH] Implement the GuardedStack marker trait. --- src/generator.rs | 34 +++++++++++++++++++++------------- src/lib.rs | 1 + src/os/mod.rs | 13 ++++++------- src/stack.rs | 6 ++++++ 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/generator.rs b/src/generator.rs index 0517e6c..c576be4 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -68,6 +68,16 @@ impl Generator where Item: Send, Stack: stack::Stack { /// Creates a new generator. pub fn new(stack: Stack, f: F) -> Generator + where Stack: stack::GuardedStack, F: FnOnce(&mut Yielder) + 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(stack: Stack, f: F) -> Generator where F: FnOnce(&mut Yielder) + Send { unsafe extern "C" fn generator_wrapper(info: usize) -> ! where Item: Send, Stack: stack::Stack, F: FnOnce(&mut Yielder) { @@ -82,21 +92,19 @@ impl Generator loop { yielder.return_(None) } } - unsafe { - let mut generator = Generator { - state: State::Suspended, - context: context::Context::new(stack, generator_wrapper::), - phantom: PhantomData - }; + let mut generator = Generator { + state: State::Suspended, + context: context::Context::new(stack, generator_wrapper::), + phantom: PhantomData + }; - // Transfer environment to the callee. - let mut data = (Yielder::new(&mut generator.context), f); - context::Context::swap(&mut generator.context, &generator.context, - &mut data as *mut (Yielder, F) as usize); - mem::forget(data); + // Transfer environment to the callee. + let mut data = (Yielder::new(&mut generator.context), f); + context::Context::swap(&mut generator.context, &generator.context, + &mut data as *mut (Yielder, F) as usize); + mem::forget(data); - generator - } + generator } /// Returns the state of the generator. diff --git a/src/lib.rs b/src/lib.rs index 2bdf621..101745d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ extern crate std; pub use stack::Stack; +pub use stack::GuardedStack; pub use context::Context; pub use generator::Generator; diff --git a/src/os/mod.rs b/src/os/mod.rs index 67c7af0..dd29536 100644 --- a/src/os/mod.rs +++ b/src/os/mod.rs @@ -7,11 +7,8 @@ use stack; 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. -/// -/// The stack it provides comes with a guard page, which is not included -/// in the stack limit. #[derive(Debug)] pub struct Stack { ptr: *mut u8, @@ -22,9 +19,9 @@ unsafe impl Send for Stack {} impl Stack { /// Allocates a new stack with at least `size` accessible bytes. - /// `size` is rounded up to an integral number of pages; `Stack::new(0)` - /// is legal and allocates the smallest possible stack, consisting - /// of one data page and one guard page. + /// `size` is rounded up to an integral number of pages; `Stack::new(0)` is legal + /// and allocates the smallest possible stack, consisting of one data page and + /// one guard page. pub fn new(size: usize) -> Result { 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 { fn drop(&mut self) { unsafe { sys::unmap_stack(self.ptr, self.len) }.expect("cannot unmap stack") diff --git a/src/stack.rs b/src/stack.rs index 116542d..fca5ed0 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -14,3 +14,9 @@ pub trait Stack { /// so this is the lowest address. 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 {}