10

It's common knowledge that returning a pointer to a stack variable is generally a bad idea:

int* foo() {
  int i = 0;
  return &i;
}

int main() {
  int* p = foo();
}

In the example above, my understanding is that the int is destroyed and so p is a dangling pointer.

I am wondering about the extent to which this applies to the newly introduced coroutines of C++20:

generator<span<byte>> read(stream& s) {
  array<byte, 4096> b;
  while (s.is_open()) {
    const size_t n = s.read_some(b);
    co_yield span(b, n);
  }
}

int main() {
  stream s;
  for (span<byte> v : read(s)) {
    /* ... */
  }
}

In this example, the coroutine read yields a span view into the local buffer b. Internally, that view stores a pointer to the buffer. Will that pointer ever be dangling when v is used with the body of the range-for loop?

For context, the coroutine code in the second example is modeled after the code in my own project. There, AddressSanitizer ends the program with a "use-after-free" error. Ordinarily I'd consider that enough to answer my question, but since coroutine development is still coming along at this point in time (my project is using boost::asio::experimental::coro, emphasis on "experimental"), I was wondering if the error was caused by a bug with generator's implementation or if returning pointers in this way is fundamentally incorrect (similar to the first example).

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
user118534
  • 101
  • 2
  • If you take for example the `Generator` implementation at https://en.cppreference.com/w/cpp/language/coroutines, then I don't see any issue. Although it caches the yielded value, the coroutine progresses to the final suspension point (where `b`'s lifetime ends) only when `operator bool` is called and going to return `false`, corresponding to the final condition test in the range-for, which should be evaluated only after the last iteration of the loop body. So it seems to me that your `generator` implementation is just faulty. (`co_return` would be different) – user17732522 Jun 11 '22 at 11:35

1 Answers1

2

With language coroutines, this has to be safe: the lifetime of b must continue until the generator is finished, so pointers to it must be useful that long.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76