Repository navigation
fix: correct the workaround gate for symmetric transfer on MSVC - #437
mvandeberg wants to merge 1 commit into
Conversation
|
An automated preview of the documentation is available at https://437.capy.prtest3.cppalliance.org/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-10-20 19:59:25 UTC |
|
GCOVR code coverage report https://437.capy.prtest3.cppalliance.org/gcovr/index.html Build time: 2026-10-20 20:12:57 UTC |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #437 +/- ##
===========================================
+ Coverage 98.39% 98.45% +0.05%
===========================================
Files 137 137
Lines 7297 7293 -4
===========================================
Hits 7180 7180
+ Misses 117 113 -4
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 12 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
2dd9f79 to
17fecda
Compare
detail::symmetric_transfer resumed on the current stack for every compiler that defines _MSC_VER. Only two MSVC defects need it: - MSVC 19.34 through 19.44, every target: the returned handle is stored on the coroutine frame, so destroying the frame in await_suspend and then transferring touches freed memory. MSVC 19.50 fixes this. - MSVC 19.50 and later on ARM64, release builds: a try region that spans the suspend point loses its handler when the coroutine is resumed from another call stack. clang-cl and clang++ targeting Windows define _MSC_VER but have neither defect. Add BOOST_CAPY_MSVC, defined only on Microsoft's compiler, so MSVC workarounds exclude Clang without a separate check; the frame allocator gate uses it too. The two defects combine into BOOST_CAPY_SYMMETRIC_TRANSFER_WORKAROUND. Add a regression test for each defect. Refs cppalliance#378
17fecda to
2904dd9
Compare
detail::symmetric_transferapplied the workaround to each compiler that defines_MSC_VER. This was too wide. MSVC has two different defects, and the new gate keeps the workaround for each one:The first defect occurs on MSVC 19.34 to 19.44, on all architectures. The caller puts the hidden return slot of
await_suspendon the coroutine frame, at__coro_frame_ptr$ + 0xC0. Whenawait_suspenddestroys that frame, the runtime then reads released memory. MSVC 19.50 puts the slot on the stack, thus the workaround retires there.The second defect occurs on MSVC 19.51 for ARM64, in release builds only. A
tryregion that spans the suspend point loses its handler. When the coroutine resumes from a different call stack, athrowin that region does not go to the adjacentcatch. The exception goes tounhandled_exceptionof the promise. Acatch(...)also does not get it, thus the runtime does not find the region at all. Debug builds are correct, and so are x64 builds at the same toolset. The gate includes_M_ARM64ECbecause that target also emits ARM64 code.The gate excludes Clang.
clang-clandclang++define_MSC_VERfor ABI compatibility, but they emit a correct tail-call.Two tests cover the defects:
test/unit/detail/await_suspend_helper.cppdestroys the coroutine frame inawait_suspendand then transfers. The test unmaps each frame on destruction, thus every subsequent access gives a fault. A poison pattern is not sufficient, becausesymmetric_transfermoves the write to the frame to a point after the destruction.test/unit/task.cppawaits a handle-returning awaitable in atryblock, resumes the parked handle from a different call stack, and then throws. The test watches for an escape through the error handler ofrun_async. A failure thus gives an assertion and not a terminate, which keeps the other results.Refs #378