Fedor
Fedor

Reputation: 21307

Is it legal to return address of local coroutine variable in C++?

If I return address of a local coroutine variable, e.g. via the promise, is it guaranteed to work by C++ standard? Consider an example (based on https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html):

#include <coroutine>
#include <iostream>

struct ReturnObject {
  struct promise_type {
    unsigned * value_ = nullptr;

    void return_void() {}
    ReturnObject get_return_object() {
      return {
        .h_ = std::coroutine_handle<promise_type>::from_promise(*this)
      };
    }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    void unhandled_exception() {}
  };

  std::coroutine_handle<promise_type> h_;
  operator auto() const { return h_; }
};

template<typename PromiseType>
struct GetPromise {
  PromiseType *p_;
  bool await_ready() { return false; }
  bool await_suspend(std::coroutine_handle<PromiseType> h) {
    p_ = &h.promise();
    return false;
  }
  PromiseType *await_resume() { return p_; }
};

ReturnObject counter()
{
  auto pp = co_await GetPromise<ReturnObject::promise_type>{};

  for (unsigned i = 0;; ++i) {
    pp->value_ = &i; // is it legal?
    co_await std::suspend_always{};
  }
}

int main()
{
  std::coroutine_handle<ReturnObject::promise_type> h = counter();
  auto &promise = h.promise();
  for (int i = 0; i < 5; ++i) {
    std::cout << "counter: " << *promise.value_ << std::endl;
    h();
  }
  h.destroy();
}

https://gcc.godbolt.org/z/P5PMc15qW

On practice I see that it does work, but is it really legal?

Upvotes: 4

Views: 305

Answers (2)

Caleth
Caleth

Reputation: 63039

Yes, this is legal. The local variables of counter are stored in a dynamically allocated object that h owns.

The usual caveats of the possibility of use-after-free are there, i.e. promise dangles after h.destroy().

Upvotes: 4

TheQuietestHand
TheQuietestHand

Reputation: 9

It can work in some cases but this is not as good way to write programs. Memory cell pointed to by the pointer can be (and it will probably be soon) overwritene by other variables. Try to write some code (declare some variables) before loop and check results again.

Upvotes: -3

Related Questions