Make resuming generators unsafe instead of the creation of immovable generators. Fixes #47787

This commit is contained in:
John Kåre Alsaker 2018-03-20 00:48:41 +01:00
parent a04b88d194
commit 57896abc38
30 changed files with 96 additions and 124 deletions

View file

@ -178,7 +178,7 @@ fn generator(a: &Allocator, run_count: usize) {
);
};
for _ in 0..run_count {
gen.resume();
unsafe { gen.resume(); }
}
}

View file

@ -42,9 +42,9 @@ fn t1() {
};
let n = A.load(Ordering::SeqCst);
a.resume();
unsafe { a.resume() };
assert_eq!(A.load(Ordering::SeqCst), n + 1);
a.resume();
unsafe { a.resume() };
assert_eq!(A.load(Ordering::SeqCst), n + 1);
}
@ -58,8 +58,8 @@ fn t2() {
};
let n = A.load(Ordering::SeqCst);
a.resume();
unsafe { a.resume() };
assert_eq!(A.load(Ordering::SeqCst), n);
a.resume();
unsafe { a.resume() };
assert_eq!(A.load(Ordering::SeqCst), n + 1);
}

View file

@ -16,7 +16,7 @@ fn finish<T>(mut amt: usize, mut t: T) -> T::Return
where T: Generator<Yield = ()>
{
loop {
match t.resume() {
match unsafe { t.resume() } {
GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(),
GeneratorState::Complete(ret) => {
assert_eq!(amt, 0);

View file

@ -37,7 +37,7 @@ fn t1() {
};
let n = A.load(Ordering::SeqCst);
drop(foo.resume());
drop(unsafe { foo.resume() });
assert_eq!(A.load(Ordering::SeqCst), n);
drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1);
@ -50,7 +50,7 @@ fn t2() {
};
let n = A.load(Ordering::SeqCst);
drop(foo.resume());
drop(unsafe { foo.resume() });
assert_eq!(A.load(Ordering::SeqCst), n + 1);
drop(foo);
assert_eq!(A.load(Ordering::SeqCst), n + 1);

View file

@ -35,6 +35,8 @@ fn bar2(baz: String) -> impl Generator<Yield = String, Return = ()> {
}
fn main() {
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new()));
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
unsafe {
assert_eq!(bar(String::new()).resume(), GeneratorState::Yielded(String::new()));
assert_eq!(bar2(String::new()).resume(), GeneratorState::Complete(()));
}
}

View file

@ -14,11 +14,13 @@ use std::ops::{GeneratorState, Generator};
struct W<T>(T);
// This impl isn't safe in general, but the generator used in this test is movable
// so it won't cause problems.
impl<T: Generator<Return = ()>> Iterator for W<T> {
type Item = T::Yield;
fn next(&mut self) -> Option<Self::Item> {
match self.0.resume() {
match unsafe { self.0.resume() } {
GeneratorState::Complete(..) => None,
GeneratorState::Yielded(v) => Some(v),
}

View file

@ -17,5 +17,5 @@ fn main() {
let mut a = || {
b(yield);
};
a.resume();
unsafe { a.resume() };
}

View file

@ -20,7 +20,7 @@ fn main() {
yield 2;
};
match sub_generator.resume() {
match unsafe { sub_generator.resume() } {
GeneratorState::Yielded(x) => {
yield x;
}

View file

@ -42,7 +42,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 0);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
foo.resume()
unsafe { foo.resume() }
}));
assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1);
@ -57,7 +57,7 @@ fn main() {
assert_eq!(A.load(Ordering::SeqCst), 1);
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
foo.resume()
unsafe { foo.resume() }
}));
assert!(res.is_err());
assert_eq!(A.load(Ordering::SeqCst), 1);

View file

@ -24,13 +24,13 @@ fn main() {
};
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
foo.resume()
unsafe { foo.resume() }
}));
assert!(res.is_err());
for _ in 0..10 {
let res = panic::catch_unwind(panic::AssertUnwindSafe(|| {
foo.resume()
unsafe { foo.resume() }
}));
assert!(res.is_err());
}

View file

@ -23,12 +23,12 @@ fn main() {
yield;
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
match panic::catch_unwind(move || foo.resume()) {
match panic::catch_unwind(move || unsafe { foo.resume() }) {
Ok(_) => panic!("generator successfully resumed"),
Err(_) => {}
}

View file

@ -24,7 +24,7 @@ fn simple() {
}
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -40,7 +40,7 @@ fn return_capture() {
a
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -52,11 +52,11 @@ fn simple_yield() {
yield;
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -69,11 +69,11 @@ fn yield_capture() {
yield b;
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -86,11 +86,11 @@ fn simple_yield_value() {
return String::from("foo")
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(ref s) if *s == "bar" => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -104,11 +104,11 @@ fn return_after_yield() {
return a
};
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(ref s) if *s == "foo" => {}
s => panic!("bad state: {:?}", s),
}
@ -156,11 +156,11 @@ fn send_and_sync() {
fn send_over_threads() {
let mut foo = || { yield };
thread::spawn(move || {
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(()) => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
@ -169,11 +169,11 @@ fn send_over_threads() {
let a = String::from("a");
let mut foo = || { yield a };
thread::spawn(move || {
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(ref s) if *s == "a" => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}

View file

@ -13,14 +13,14 @@
use std::ops::{Generator, GeneratorState};
fn main() {
let mut generator = unsafe {
static || {
let a = true;
let b = &a;
yield;
assert_eq!(b as *const _, &a as *const _);
}
let mut generator = static || {
let a = true;
let b = &a;
yield;
assert_eq!(b as *const _, &a as *const _);
};
assert_eq!(generator.resume(), GeneratorState::Yielded(()));
assert_eq!(generator.resume(), GeneratorState::Complete(()));
unsafe {
assert_eq!(generator.resume(), GeneratorState::Yielded(()));
assert_eq!(generator.resume(), GeneratorState::Complete(()));
}
}

View file

@ -17,5 +17,5 @@ extern crate xcrate_reachable as foo;
use std::ops::Generator;
fn main() {
foo::foo().resume();
unsafe { foo::foo().resume(); }
}

View file

@ -19,18 +19,18 @@ use std::ops::{GeneratorState, Generator};
fn main() {
let mut foo = xcrate::foo();
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}
let mut foo = xcrate::bar(3);
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Yielded(3) => {}
s => panic!("bad state: {:?}", s),
}
match foo.resume() {
match unsafe { foo.resume() } {
GeneratorState::Complete(()) => {}
s => panic!("bad state: {:?}", s),
}

View file

@ -15,7 +15,7 @@ use std::ops::Generator;
fn main() {
let _b = {
let a = 3;
(|| yield &a).resume()
unsafe { (|| yield &a).resume() }
//~^ ERROR: `a` does not live long enough
};

View file

@ -1,10 +1,10 @@
error[E0597]: `a` does not live long enough
--> $DIR/borrowing.rs:18:20
--> $DIR/borrowing.rs:18:29
|
LL | (|| yield &a).resume()
| -- ^ borrowed value does not live long enough
| |
| capture occurs here
LL | unsafe { (|| yield &a).resume() }
| -- ^ borrowed value does not live long enough
| |
| capture occurs here
LL | //~^ ERROR: `a` does not live long enough
LL | };
| - borrowed value only lives until here

View file

@ -23,6 +23,6 @@ fn main() {
let _d = ref_.take(); //~ ERROR `ref_` does not live long enough
yield;
};
gen.resume();
unsafe { gen.resume(); }
// drops the RefCell and then the Ref, leading to use-after-free
}

View file

@ -17,5 +17,5 @@ fn main() {
let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
yield s[..];
};
gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
}

View file

@ -11,10 +11,10 @@ LL | | };
= note: the yield type of a generator must have a statically known size
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> $DIR/sized-yield.rs:20:8
--> $DIR/sized-yield.rs:20:17
|
LL | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
| ^^^^^^ `str` does not have a constant size known at compile-time
LL | unsafe { gen.resume(); } //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
| ^^^^^^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`

View file

@ -1,17 +0,0 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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 copied, modified, or distributed
// except according to those terms.
#![feature(generators)]
fn main() {
static || { //~ ERROR: construction of immovable generator requires unsafe
yield;
};
}

View file

@ -1,11 +0,0 @@
error[E0133]: construction of immovable generator requires unsafe function or block
--> $DIR/unsafe-immovable.rs:14:5
|
LL | / static || { //~ ERROR: construction of immovable generator requires unsafe
LL | | yield;
LL | | };
| |_____^ construction of immovable generator
error: aborting due to previous error
For more information about this error, try `rustc --explain E0133`.

View file

@ -43,7 +43,7 @@ fn yield_during_iter_borrowed_slice_2() {
println!("{:?}", x);
}
fn yield_during_iter_borrowed_slice_3() {
unsafe fn yield_during_iter_borrowed_slice_3() {
// OK to take a mutable ref to `x` and yield
// up pointers from it:
let mut x = vec![22_i32];
@ -55,7 +55,7 @@ fn yield_during_iter_borrowed_slice_3() {
b.resume();
}
fn yield_during_iter_borrowed_slice_4() {
unsafe fn yield_during_iter_borrowed_slice_4() {
// ...but not OK to do that while reading
// from `x` too
let mut x = vec![22_i32];
@ -68,7 +68,7 @@ fn yield_during_iter_borrowed_slice_4() {
b.resume();
}
fn yield_during_range_iter() {
unsafe fn yield_during_range_iter() {
// Should be OK.
let mut b = || {
let v = vec![1,2,3];

View file

@ -15,7 +15,7 @@
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
fn borrow_local_inline() {
unsafe fn borrow_local_inline() {
// Not OK to yield with a borrow of a temporary.
//
// (This error occurs because the region shows up in the type of
@ -30,7 +30,7 @@ fn borrow_local_inline() {
b.resume();
}
fn borrow_local_inline_done() {
unsafe fn borrow_local_inline_done() {
// No error here -- `a` is not in scope at the point of `yield`.
let mut b = move || {
{
@ -41,7 +41,7 @@ fn borrow_local_inline_done() {
b.resume();
}
fn borrow_local() {
unsafe fn borrow_local() {
// Not OK to yield with a borrow of a temporary.
//
// (This error occurs because the region shows up in the type of

View file

@ -13,7 +13,7 @@
use std::ops::{GeneratorState, Generator};
use std::cell::Cell;
fn reborrow_shared_ref(x: &i32) {
unsafe fn reborrow_shared_ref(x: &i32) {
// This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator.
let mut b = move || {
@ -24,7 +24,7 @@ fn reborrow_shared_ref(x: &i32) {
b.resume();
}
fn reborrow_mutable_ref(x: &mut i32) {
unsafe fn reborrow_mutable_ref(x: &mut i32) {
// This is OK -- we have a borrow live over the yield, but it's of
// data that outlives the generator.
let mut b = move || {
@ -35,7 +35,7 @@ fn reborrow_mutable_ref(x: &mut i32) {
b.resume();
}
fn reborrow_mutable_ref_2(x: &mut i32) {
unsafe fn reborrow_mutable_ref_2(x: &mut i32) {
// ...but not OK to go on using `x`.
let mut b = || {
let a = &mut *x;