Work around MSVC symmetric transfer use-after-free in transform_awaiter#179
Work around MSVC symmetric transfer use-after-free in transform_awaiter#179sgerbino merged 1 commit intocppalliance:developfrom
Conversation
MSVC stores the coroutine_handle<> return value from await_suspend on the coroutine frame via hidden __$ReturnUdt$. After await_suspend publishes the coroutine handle to another thread (e.g. via IOCP), that thread can resume/destroy the frame before __resume reads the handle back for the symmetric transfer tail-call, causing a use-after-free. On MSVC, call the returned handle's resume() on the machine stack instead of returning it for symmetric transfer. For IOCP awaitables that return noop_coroutine(), this is a no-op.
📝 WalkthroughWalkthroughIntroduces MSVC-specific conditional logic in three header files' Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
An automated preview of the documentation is available at https://179.capy.prtest3.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-02-23 14:21:02 UTC |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
include/boost/capy/when_any.hpp (1)
356-364: Same missing-comment issue aswhen_all.hpp.Add the MSVC
__$ReturnUdt$workaround comment for parity withtask.hpplines 208–213.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@include/boost/capy/when_any.hpp` around lines 356 - 364, Add the same MSVC __$ReturnUdt$ workaround comment used in task.hpp near the await_suspend handling: above the conditional around using R = decltype(a_.await_suspend(h, &p_->env_)); and the specialized resume/return paths, insert the explanatory comment about MSVC emitting a bogus __$ReturnUdt$ return type and why the conditional/resume branch is required so readers understand the platform-specific workaround for a_.await_suspend(h, &p_->env_).include/boost/capy/when_all.hpp (1)
218-226: Add the explanatory comment fromtask.hppfor consistency.
task.hpplines 208–213 include a clear explanation of the MSVC__$ReturnUdt$use-after-free. This site has the same workaround but no comment. Future maintainers encountering this#ifdefblock need to understand why it exists.Suggested diff
`#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_->env_));🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@include/boost/capy/when_all.hpp` around lines 218 - 226, The MSVC-specific `#ifdef` block around a_.await_suspend in when_all.hpp lacks the explanatory comment present in task.hpp about the MSVC __$ReturnUdt$ use-after-free bug; add the same explanatory comment (or an appropriately adjusted variant) above the _MSC_VER branch explaining why we call and resume the returned std::coroutine_handle<> instead of returning it and how this avoids the __$ReturnUdt$ use-after-free; locate the block around a_.await_suspend(h, &p_->env_) (references: a_.await_suspend, p_->env_, _MSC_VER) and insert the comment text from task.hpp lines 208–213 for consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@include/boost/capy/when_all.hpp`:
- Around line 218-226: The MSVC-specific `#ifdef` block around a_.await_suspend in
when_all.hpp lacks the explanatory comment present in task.hpp about the MSVC
__$ReturnUdt$ use-after-free bug; add the same explanatory comment (or an
appropriately adjusted variant) above the _MSC_VER branch explaining why we call
and resume the returned std::coroutine_handle<> instead of returning it and how
this avoids the __$ReturnUdt$ use-after-free; locate the block around
a_.await_suspend(h, &p_->env_) (references: a_.await_suspend, p_->env_,
_MSC_VER) and insert the comment text from task.hpp lines 208–213 for
consistency.
In `@include/boost/capy/when_any.hpp`:
- Around line 356-364: Add the same MSVC __$ReturnUdt$ workaround comment used
in task.hpp near the await_suspend handling: above the conditional around using
R = decltype(a_.await_suspend(h, &p_->env_)); and the specialized resume/return
paths, insert the explanatory comment about MSVC emitting a bogus __$ReturnUdt$
return type and why the conditional/resume branch is required so readers
understand the platform-specific workaround for a_.await_suspend(h, &p_->env_).
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
include/boost/capy/task.hppinclude/boost/capy/when_all.hppinclude/boost/capy/when_any.hpp
|
GCOVR code coverage report https://179.capy.prtest3.cppalliance.org/gcovr/index.html Build time: 2026-02-23 14:33:09 UTC |
MSVC stores the coroutine_handle<> return value from await_suspend on the coroutine frame via hidden __$ReturnUdt$. After await_suspend publishes the coroutine handle to another thread (e.g. via IOCP), that thread can resume/destroy the frame before __resume reads the handle back for the symmetric transfer tail-call, causing a use-after-free.
On MSVC, call the returned handle's resume() on the machine stack instead of returning it for symmetric transfer. For IOCP awaitables that return noop_coroutine(), this is a no-op.
Summary by CodeRabbit
Bug Fixes