Closed
Description
extern crate futures;
extern crate tokio_core;
use futures::{future, Future};
use tokio_core::reactor::Core;
pub trait Action {
type Output: Future<Item = (), Error = ()>;
fn run(self) -> Self::Output;
}
impl<T: Future<Item=(), Error=()>, F: FnOnce() -> T> Action for F {
type Output = T;
fn run(self) -> Self::Output {
self()
}
}
fn retry<A: Action>(action: A) -> impl Future<Item = (), Error = ()> {
action.run()
}
/*
The `lazy` closure avoids the check of its lifetime here, if:
- the `lazy` closure is nested into the `action` closure, and
- the `action` closure is passed into the `retry` function, and
- the `retry` function take a generic by the `Action` trait argument, and
- the `Action` trait is implemented for an `Fn*` trait.
As a result, we get arbitrary values in variables and at best SIGSEGV.
*/
fn main() {
let mut core = Core::new().unwrap();
let handle = core.handle();
for i in &[1, 2, 3, 4, 5] {
println!("outer: {}", i);
let f = move || {
println!("inner: {}", i);
future::ok::<(), ()>(())
};
let action = move || {
future::lazy(|| { // The `lazy` closure
f()
})
};
handle.spawn(retry(action))
}
core.run(future::empty::<(), ()>()).expect("Core::run");
}
Output:
outer: 1
outer: 2
outer: 3
outer: 4
outer: 5
inner: 1027752016
inner: 1027752016
inner: 1027752016
inner: 1027752016
inner: 1027752016
Errors:
Compiling playground v0.0.1 (file:///playground)
Finished dev [unoptimized + debuginfo] target(s) in 2.29s
Running `target/debug/playground`
/root/entrypoint.sh: line 8: 8 Killed timeout --signal=KILL ${timeout} "$@"
This emits a warning in the 2018 edition mode, but silently accepts code leading to UB in the 2015 edition.