2

godbolt: https://godbolt.org/z/6avWcGqKv

The following code, compiled and run with g++ 12, 13, 14, all give the same (wrong?) output.

clang 18, 19 are fine (all "done: 1").

As far as I understand, since the initial_suspend() is suspend_never, after creation, the promise runs immediately to final_suspend, and should return "true" when querying "done()", but one of them does not. Is it my programming error, or compiler error, or some UB, or something?

Program returned: 0
done: 1
done: 1
done: 1
done: 1
done: 1
done: 0  <-- ???
done: 1
done: 1
done: 1
done: 1

code:

#include <coroutine>
#include <iostream>
#include <vector>

struct Task {
  struct promise_type {
    Task get_return_object() {
      return {.h = std::coroutine_handle<>::from_address(this)};
    }
    std::suspend_never initial_suspend() noexcept { return {}; }
    std::suspend_always final_suspend() noexcept { return {}; }
    void unhandled_exception() {}
    void return_void() {}
  };
  std::coroutine_handle<> h;
};

Task coro() { co_return; }

int main() {
  std::vector<Task> v;
  for (int i = 0; i < 10; ++i)
    v.push_back(coro());
  for (auto &t : v)
    std::cout << "done: "<< t.h.done() << "\n";

  return 0;
}
8
  • Clang's memory sanitizer warns about uninitialized variable godbolt.org/z/8Ma5Yzxzb Commented Oct 18, 2024 at 14:27
  • as far as i understand, since the initial_suspend() is suspend_never, after creation, the promise runs immediately to final_suspend, and should return "true" when querying "done()", but one of the do not Commented Oct 18, 2024 at 14:28
  • 1
    Are you sure std::coroutine_handle<>::from_address(this) is correct? cppreference says it must be an address of a handle, you are passing address of promise_type? This example uses from_promise in your context. Commented Oct 18, 2024 at 14:31
  • I'm used to be sure, not not anymore ;-), isn't that what from_address is designed for? Commented Oct 18, 2024 at 14:35
  • 1
    from_address: The behavior is undefined if addr is neither a null pointer value nor an underlying address of a coroutine_handle. en.cppreference.com/w/cpp/coroutine/coroutine_handle/… Commented Oct 18, 2024 at 14:39

2 Answers 2

3

Per cppreference, std::coroutine_handle<Promise>::from_address can only be passed the result of another's (compatible) handle std::coroutine_handle<Promise>::address but you are passing the address of promise_type. To reconstruct the handle from that, you need std::coroutine_handle<Promise>::from_promise

Task get_return_object() {
      return { std::coroutine_handle<promise_type>::from_promise(*this)};
    }

returns all ones with gcc https://godbolt.org/z/9E8aMdK1v

The original code compiled with clang and -fsanitize=memory complained about:

==1==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x55555561f462 in std::ostream::operator<<(bool) /opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/ostream:183:16
    #1 0x55555561f462 in main /app/example.cpp:25:26
    #2 0x7ffff7829d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
    #3 0x7ffff7829e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 490fef8403240c91833978d494d39e537409b92e)
    #4 0x555555586324 in _start (/app/output.s+0x32324)

SUMMARY: MemorySanitizer: use-of-uninitialized-value /app/example.cpp:25:26 in main
Exiting
Sign up to request clarification or add additional context in comments.

Comments

0

well, turns out

  return {.h = std::coroutine_handle<>::from_address(this)};

is UB, thanks @NathanOliver

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.