Issue 177023
Summary Enable `lifetimebound` analysis to go through `operator co_await` into `await_resume`
Labels new issue
Assignees
Reporter snarkmaster
    Currently, `lifetimebound` analysis does not propagate through calls to `operator co_await`: https://godbolt.org/z/nnj6vnovx -- full code below. In short, imagine `Awaiter` that stores a reference, and correctly uses `lifetimebound` on its ctor and `await_resume`. Then:

```cpp
auto&& r1 = co_await Awaiter{tmp()};        // BAD: No warning!
auto&& r2 = Awaiter{tmp()}.await_resume();  // -Wdangling
```

The desired outcome is for both lines to emit `-Wdangling`.

Real-world user code looks like this, and hits an ASAN failure, which can be too little too late:

```cpp
auto temp = [] { return ResultT<std::string>{"will dangle"}; };
auto&& ref = co_await or_unwind(temp());
EXPECT_EQ("hello_dangling_test", ref); // ASAN: use-after-free
```

My questions: 
 - Is this a simple fix? 
 - If so, has anyone got the time and generosity to put up a PR?
 - Or, if it's simple, but you don't have time for a PR, I *might* be able to take it on with the following pointers:
    * What code & tests to change
    * Any pitfalls
    * Expected time for an experienced contributor to do commit this same PR (I'd just multiply my own time by 10x lol)

Thank you very much for any help with this!

```cpp
#include <coroutine>
#include <string>

struct Coro {
    struct promise_type {
 std::suspend_never initial_suspend() noexcept { return {}; }
 std::suspend_never final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
        auto get_return_object() {
            return std::coroutine_handle<promise_type>::from_promise(*this);
        }
 };
    std::coroutine_handle<promise_type> h;
 Coro(std::coroutine_handle<promise_type> h) : h(h) {}
};

template <typename T>
struct Awaiter {
    T&& ref;

    explicit Awaiter(T&& r [[clang::lifetimebound]]) noexcept
        : ref(static_cast<T&&>(r)) {}

 bool await_ready() const noexcept { return true; }
    void await_suspend(std::coroutine_handle<>) noexcept {}

    // lifetimebound says: returned ref should not outlive `this`
    T&& await_resume() const noexcept [[clang::lifetimebound]] {
        return static_cast<T&&>(ref);
 }
};

std::string tmp() { return "test"; }

Coro test_coro() {
 [[maybe_unused]] auto&& r1 = co_await Awaiter{tmp()};  // BAD: No warning!
 [[maybe_unused]] auto&& r2 = Awaiter{tmp()}.await_resume();  // -Wdangling
}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to