workaround: task use-after-free on MSVC due to symmetric transfer codegen bug#2020
Closed
lixin-wei wants to merge 1 commit intoNVIDIA:mainfrom
Closed
workaround: task use-after-free on MSVC due to symmetric transfer codegen bug#2020lixin-wei wants to merge 1 commit intoNVIDIA:mainfrom
lixin-wei wants to merge 1 commit intoNVIDIA:mainfrom
Conversation
MSVC does not implement symmetric transfer as a true tail call (DevCom #10454102). When await_suspend returns coroutine_handle<>, MSVC writes the returned handle back into the suspended coroutine's frame before transferring to it. In task<T>'s __completed_awaiter, __completed() frees the coroutine frame (via __sink, or indirectly through the set_value/set_error/set_stopped completion chain), so that write hits freed memory -- a use-after-free that causes crashes under concurrent task completions. Fix: on MSVC, use the void-returning await_suspend overload and call resume() explicitly. This avoids the stale write entirely. Trade-off: this loses MSVC's (already non-tail-call) symmetric transfer in __completed_awaiter, so deeply nested co_await chains of task<T> within task<T> will grow the call stack O(N) instead of O(1). The stack overflow test iteration count is reduced on MSVC accordingly. Also adds two regression tests that exercise concurrent task completion paths (flat spawn_future + recursive tree) to cover the bug. Made-with: Cursor
Contributor
Author
|
it's fixed in 1950, closing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Problem
I met a segment fault on MSVC (_MSC_VER 1944)
The root cause seems to be a bug of MSVC's code generation in symmetric transfer. It generates something like:
That intermediate write back into the suspended coroutine's frame is the problem. In stdexec's task, await_suspend calls __completed(), which destroys the coroutine frame (via __sink(task)) as part of its cleanup. When await_suspend returns, the frame is already freed — but MSVC still writes the returned handle into it, causing a write-after-free crash.
I've searched around but this bug seems not fixed yet.
The Workaround
This PR makes a workaround by disabling symmetric transfer in MSVC.
But this will cause the
test_task_awaits_inline_sndr_without_stack_overflowto fail, which tests symmetric transfer. So I also disabled this test in MSVC.