fix: narrow the symmetric-transfer workaround to MSVC < 19.50, exclud… - #427
mvandeberg wants to merge 1 commit into
Conversation
…e Clang
detail::symmetric_transfer substituted h.resume() on the current stack
for any compiler defining _MSC_VER, trading O(1) tail-calls for O(n)
stack growth. That over-matched on two axes.
MSVC 19.34 through 19.44 place await_suspend's hidden return slot on
the coroutine frame, at __coro_frame_ptr$ + 0xC0, so an await_suspend
that destroys its own frame and then transfers leaves the write and
read-back of the returned handle pointing at freed memory. MSVC 19.50
makes that slot an rsp-relative stack temporary which outlives the
frame, so the workaround no longer applies.
clang-cl and clang++ targeting Windows define _MSC_VER for ABI
compatibility but emit a correct tail-call, so they never needed the
workaround. A version-only gate would not exclude them, since Clang
continues to emulate a sub-1950 _MSC_VER.
The gate becomes:
BOOST_CAPY_WORKAROUND(_MSC_VER, < 1950) && !defined(__clang__)
Adds a regression test for the shape when_all_runner and
when_any_runner use in final_suspend: destroy the frame inside
await_suspend, then transfer through symmetric_transfer. Frames are
allocated with VirtualAlloc/mmap and unmapped on destroy so that any
post-destroy access faults. A poisoning allocator cannot detect this
case, because routing the return through symmetric_transfer moves the
compiler's write into the frame slot to after destroy, which repairs
the poison and hides the defect.
Adds MSVC 14.51 (VS 2026) to the CI matrix on windows-2025-vs2026,
which is the only configuration that exercises the newly enabled
tail-call path. It builds with Ninja because the CMake that
cmake-workflow selects on that image predates the Visual Studio 18
2026 generator. is_latest moves from 14.44 to 14.51, taking the MSVC
CMake and ASan variants with it; Visual Studio generator coverage
remains on 14.34.
Includes detail/config.hpp explicitly rather than relying on it
arriving through ex/io_env.hpp.
Refs cppalliance#378
|
An automated preview of the documentation is available at https://427.capy.prtest3.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-09-22 17:09:48 UTC |
|
GCOVR code coverage report https://427.capy.prtest3.cppalliance.org/gcovr/index.html Build time: 2026-09-22 17:16:17 UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #427 +/- ##
========================================
Coverage 98.09% 98.09%
========================================
Files 130 130
Lines 6289 6289
========================================
Hits 6169 6169
Misses 120 120
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 1 file with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
…e Clang
detail::symmetric_transfer substituted h.resume() on the current stack for any compiler defining _MSC_VER, trading O(1) tail-calls for O(n) stack growth. That over-matched on two axes.
MSVC 19.34 through 19.44 place await_suspend's hidden return slot on the coroutine frame, at __coro_frame_ptr$ + 0xC0, so an await_suspend that destroys its own frame and then transfers leaves the write and read-back of the returned handle pointing at freed memory. MSVC 19.50 makes that slot an rsp-relative stack temporary which outlives the frame, so the workaround no longer applies.
clang-cl and clang++ targeting Windows define _MSC_VER for ABI compatibility but emit a correct tail-call, so they never needed the workaround. A version-only gate would not exclude them, since Clang continues to emulate a sub-1950 _MSC_VER.
The gate becomes:
Adds a regression test for the shape when_all_runner and when_any_runner use in final_suspend: destroy the frame inside await_suspend, then transfer through symmetric_transfer. Frames are allocated with VirtualAlloc/mmap and unmapped on destroy so that any post-destroy access faults. A poisoning allocator cannot detect this case, because routing the return through symmetric_transfer moves the compiler's write into the frame slot to after destroy, which repairs the poison and hides the defect.
Adds MSVC 14.51 (VS 2026) to the CI matrix on windows-2025-vs2026, which is the only configuration that exercises the newly enabled tail-call path. It builds with Ninja because the CMake that cmake-workflow selects on that image predates the Visual Studio 18 2026 generator. is_latest moves from 14.44 to 14.51, taking the MSVC CMake and ASan variants with it; Visual Studio generator coverage remains on 14.34.
Includes detail/config.hpp explicitly rather than relying on it arriving through ex/io_env.hpp.
Refs #378