1
0
Fork 0

Leak the stack if it's unsafe to drop it

We can't free the stack before the generator has returned, or been
unwound. Without unwinding, the only safe course of action is to leak
it.
This commit is contained in:
edef 2017-02-25 14:09:35 +01:00
parent 785c7b516a
commit 4813dd7411
2 changed files with 46 additions and 8 deletions

View File

@ -82,12 +82,27 @@ pub enum State {
#[derive(Debug)] #[derive(Debug)]
pub struct Generator<'a, Input: 'a, Output: 'a, Stack: stack::Stack> { pub struct Generator<'a, Input: 'a, Output: 'a, Stack: stack::Stack> {
state: State, state: State,
stack: Stack, stack: NoDrop<Stack>,
stack_id: debug::StackId, stack_id: NoDrop<debug::StackId>,
stack_ptr: arch::StackPointer, stack_ptr: arch::StackPointer,
phantom: PhantomData<(&'a (), *mut Input, *const Output)> phantom: PhantomData<(&'a (), *mut Input, *const Output)>
} }
#[allow(unions_with_drop_fields)]
union NoDrop<T> {
value: T,
_empty: ()
}
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for NoDrop<T> {
fn fmt(&self, w: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
unsafe {
// this is safe because we never invoke formatting on the empty variant
self.value.fmt(w)
}
}
}
impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack> impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
where Input: 'a, Output: 'a, Stack: stack::Stack { where Input: 'a, Output: 'a, Stack: stack::Stack {
/// Creates a new generator. /// Creates a new generator.
@ -131,8 +146,8 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
Generator { Generator {
state: State::Runnable, state: State::Runnable,
stack: stack, stack: NoDrop { value: stack },
stack_id: stack_id, stack_id: NoDrop { value: stack_id },
stack_ptr: stack_ptr, stack_ptr: stack_ptr,
phantom: PhantomData phantom: PhantomData
} }
@ -151,7 +166,7 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
// Switch to the generator function, and retrieve the yielded value. // Switch to the generator function, and retrieve the yielded value.
let val = unsafe { let val = unsafe {
let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack)); let (data_out, stack_ptr) = arch::swap(&input as *const Input as usize, self.stack_ptr, Some(&self.stack.value));
self.stack_ptr = stack_ptr; self.stack_ptr = stack_ptr;
mem::forget(input); mem::forget(input);
ptr::read(data_out as *const Option<Output>) ptr::read(data_out as *const Option<Output>)
@ -176,8 +191,31 @@ impl<'a, Input, Output, Stack> Generator<'a, Input, Output, Stack>
/// (i.e. `self.state() == State::Runnable`), panics. /// (i.e. `self.state() == State::Runnable`), panics.
pub fn unwrap(self) -> Stack { pub fn unwrap(self) -> Stack {
match self.state { match self.state {
State::Runnable => panic!("Argh! Bastard! Don't touch that!"), State::Runnable => {
State::Unavailable => self.stack mem::forget(self);
panic!("Argh! Bastard! Don't touch that!")
}
State::Unavailable => unsafe { self.unsafe_unwrap() }
}
}
unsafe fn unsafe_unwrap(mut self) -> Stack {
ptr::drop_in_place(&mut self.stack_id.value);
let stack = ptr::read(&mut self.stack.value);
mem::forget(self);
stack
}
}
impl<'a, Input, Output, Stack> Drop for Generator<'a, Input, Output, Stack>
where Input: 'a, Output: 'a, Stack: stack::Stack {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(&mut self.stack_id.value);
match self.state {
State::Runnable => {} // leak the stack
State::Unavailable => ptr::drop_in_place(&mut self.stack.value)
}
} }
} }
} }

View File

@ -4,7 +4,7 @@
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be // http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms. // copied, modified, or distributed except according to those terms.
#![feature(asm, naked_functions, cfg_target_vendor)] #![feature(asm, naked_functions, cfg_target_vendor, untagged_unions)]
#![cfg_attr(feature = "alloc", feature(alloc, heap_api))] #![cfg_attr(feature = "alloc", feature(alloc, heap_api))]
#![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(test))]
#![no_std] #![no_std]