C++ Logo

std-proposals

Advanced search

async coroutines vs. lambdas

From: Avi Kivity <avi_at_[hidden]>
Date: Thu, 14 May 2020 13:57:32 +0300
Coroutines capture parameters passed by value and copy them to the
coroutine frame (all quotes from cppreference):


> When a coroutine begins execution, it performs the following:
>
> allocates the coroutine state object using operator new (see below)
> copies all function parameters to the coroutine state: by-value
parameters are moved or copied, by-reference parameters remain
references (and so may become dangling if the coroutine is resumed after
the lifetime of referred object ends)
>

This allows a coroutine's parameters to outlive the point it is launched at:


void foo() {

     call_some_coroutine(a_temporary_value());

}


Normally, a_temporary_value() would e destroyed at the end of the
expression, which can be before the coroutine completes.


With a lambda coroutine, we have a problem. This is because lambdas are
captured by reference:


> If the coroutine is a non-static member function, such as task<void>
my_class::method1(int x) const;, its Promise type is
std::coroutine_traits<task<void>, const my_class&, int>::promise_type


For a lambda, the non-static member function is
synthetic_lambda_type::operator() const, and so the lambda would be
captured as const synthetic_lambda_type&. Consider this call:


int var;


void foo() {

     [i = 3] () -> future<> {

         co_await delay(1s);

         var = i;

     }();

}


Because the lambda is captured by reference, the read of 'i' refers to a
freed stack frame.


I consider this is a serious defect. It can be fixed by changing how
"this" parameters to member functions are captured:


  - if the object is an rvalue[1], then it is captured by value (and the
promise type is std::coroutine_traits<task<void>, const my_class,
int>::promise_type

  - if the object is a glvalue, then it is captured by reference (and
the promise type is std::coroutine_traits<task<void>, const my_class&,
int>::promise_type


I filed a bug[2] against gcc regarding this, but I now believe gcc to be
innocent.


[1] I'm not up to speed on C++ value categories so I'm not sure if this
is a prvalue, xvalue, rvalue, or something else.

[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95111

Received on 2020-05-14 06:00:38