diff --git a/include/boost/capy/task.hpp b/include/boost/capy/task.hpp index 97d4cf1f..db4c25f1 100644 --- a/include/boost/capy/task.hpp +++ b/include/boost/capy/task.hpp @@ -204,7 +204,21 @@ struct [[nodiscard]] BOOST_CAPY_CORO_AWAIT_ELIDABLE template auto await_suspend(std::coroutine_handle h) noexcept { +#ifdef _MSC_VER + // Workaround: MSVC stores the coroutine_handle<> return + // value on the coroutine frame via hidden __$ReturnUdt$. + // After await_suspend publishes the handle to another + // thread, that thread can resume/destroy the frame before + // __resume reads the handle back for the symmetric + // transfer tail-call, causing a use-after-free. + using R = decltype(a_.await_suspend(h, p_->environment())); + if constexpr (std::is_same_v>) + a_.await_suspend(h, p_->environment()).resume(); + else + return a_.await_suspend(h, p_->environment()); +#else return a_.await_suspend(h, p_->environment()); +#endif } }; diff --git a/include/boost/capy/when_all.hpp b/include/boost/capy/when_all.hpp index 0f3200a5..d3cec213 100644 --- a/include/boost/capy/when_all.hpp +++ b/include/boost/capy/when_all.hpp @@ -215,7 +215,15 @@ struct when_all_runner template auto await_suspend(std::coroutine_handle h) { +#ifdef _MSC_VER + using R = decltype(a_.await_suspend(h, &p_->env_)); + if constexpr (std::is_same_v>) + a_.await_suspend(h, &p_->env_).resume(); + else + return a_.await_suspend(h, &p_->env_); +#else return a_.await_suspend(h, &p_->env_); +#endif } }; diff --git a/include/boost/capy/when_any.hpp b/include/boost/capy/when_any.hpp index 8965c1ba..2a750b3a 100644 --- a/include/boost/capy/when_any.hpp +++ b/include/boost/capy/when_any.hpp @@ -353,7 +353,15 @@ struct when_any_runner template auto await_suspend(std::coroutine_handle h) { +#ifdef _MSC_VER + using R = decltype(a_.await_suspend(h, &p_->env_)); + if constexpr (std::is_same_v>) + a_.await_suspend(h, &p_->env_).resume(); + else + return a_.await_suspend(h, &p_->env_); +#else return a_.await_suspend(h, &p_->env_); +#endif } };