You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It seems (me looking at macro expansions) that yield usage in an async {} block is not expanded by this macro, and that’s good - in principle - because it can be unsound to await that in the wrong place with the way that thread-locals are used.
However, this is a syntactic analysis, and yield in macros are expanded, so well, that can be a problem if a macro introduces an async block:
use async_stream::stream;use futures::StreamExt;use std::pin::pin;macro_rules! asynk {($e:expr) => {async{ $e }};}#[tokio::main]asyncfnmain(){pin!(stream! {let yield_42 = asynk!(yield 42_usize);let s = stream! {
yield Box::new(12345);
yield_42.await;// yield 42 -- wait that's not a Box!?};forawait(n, i) in s.enumerate(){
println!("Item at index {n}:\n {i}");// Item at index 0:// 12345// Item at index 1:// Segmentation fault}}).next().await;}
This kind of abuse could be better prevented with a trick I came up with in dureuill/nolife#8 (comment), the idea is to make the whole stream! invocation create a labelled block, and have yield include a if false guarded break from the same label; this will successfully prevent compilation in case the yield is anywhere where control-flow cannot directly jump back to the top-level of stream! (which should correspond to anywhere where the .await of the yield expansion does not correspond to the outer async block from the stream! expansion), hence preventing accidental use of yield in a nested async block.
(For nolife, the macro involved a macro_rules macro, where the default hygiene rules would successfully prevent the labels not matching up properly; I don't quite remember off the top of my head how far support for doing the same in proc-macros is nowadays.)
The text was updated successfully, but these errors were encountered:
It seems (me looking at macro expansions) that
yield
usage in anasync {}
block is not expanded by this macro, and that’s good - in principle - because it can be unsound to await that in the wrong place with the way that thread-locals are used.However, this is a syntactic analysis, and
yield
in macros are expanded, so well, that can be a problem if a macro introduces anasync
block:(run on rustexplorer.com)
This kind of abuse could be better prevented with a trick I came up with in dureuill/nolife#8 (comment), the idea is to make the whole
stream!
invocation create a labelled block, and haveyield
include aif false
guardedbreak
from the same label; this will successfully prevent compilation in case theyield
is anywhere where control-flow cannot directly jump back to the top-level ofstream!
(which should correspond to anywhere where the.await
of theyield
expansion does not correspond to the outerasync
block from thestream!
expansion), hence preventing accidental use ofyield
in a nestedasync
block.(For
nolife
, the macro involved amacro_rules
macro, where the default hygiene rules would successfully prevent the labels not matching up properly; I don't quite remember off the top of my head how far support for doing the same in proc-macros is nowadays.)The text was updated successfully, but these errors were encountered: