Repository navigation
fix(exec): own the written env in sequence write_env's operation state - #2306
Open
alwaysprince05 wants to merge 1 commit into
Open
alwaysprince05 wants to merge 1 commit into
alwaysprince05 wants to merge 1 commit into
Conversation
Subscribing to a write_env sender that wraps a sequence sender takes the transparent-adaptor path in exec::subscribe: the adaptor's data is joined with the receiver's environment and stored in the environment presented to the child. The joined environment held a reference to the data member of the sender expression itself, so once the sender expression is destroyed, the operation state is left reading dangling memory. Have __write_env_t's __child_env_fn own a decayed copy of the data -- moving out of an rvalue sender, copying from an lvalue -- and forward the sender's value category to the transformation instead of the value category of the data member binding. The unconditional noexcept on __child_env_fn::operator() becomes conditional on constructing the owned data, and the transparent branch of the subscribe machinery accounts for that construction in its computed noexcept. Refs NVIDIA#2305.
Contributor
Author
|
/ok to test |
This branch has not been deployed
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.
Part 1 of #2305 (
write_envover sequence senders). Theiteratehalf of that issue will be a separate PR. This is fallout from #2294.Problem
When a
write_envsender wraps a sequence sender,exec::subscribeunwraps the adaptor one layer at a time: the adaptor's data is joined with the receiver's environment and the result is stored in the environment presented to the child. The transparent branch joined the adaptor's data by reference —__join_env_t<_Data const&, _Env>— and the reference pointed into the sender expression. The returned operation state outlives the sender expression, so a query into the written environment aftersubscribereturns reads dangling memory:AddressSanitizer on main (f4c123f) reports heap-use-after-free for this pattern, as traced in #2305.
Fix
__write_env_t's__child_env_fnnow owns the data it puts into the child's environment:_Data— moving out of an rvalue sender, copying from an lvalue — and joins the owned value with the receiver's environment, which is what the regular (non-sequence)write_envpath already does with its__state.__data_;__forward_like<__tfx_seq_t>) rather than the value category of the structured binding of the data member;noexcepton__child_env_fn::operator()is now conditional on constructing the owned data, and the transparent branch's computednoexceptincludes that construction.A
static_assert(__nothrow_move_constructible<_Data>)guards the move that happens inside__env::__join'snoexceptbody, mirroring the constraint__fwdalready imposes on the wrapped environment.Tests
Three regression tests in
test/exec/sequence/test_write_env_sequence.cpp, all failing onmainand passing with this change:write_envsender, destroying it, then starting the operation state and reading the injected query;The tests fail deterministically on unfixed
maineven without ASAN: the env data type poisons its own value on destruction, so a read through the dangling reference returns the poison instead of the original value.Verification
test.exec(376 cases) andtest.stdexec(626 cases) green withSTDEXEC_ENABLE_EXTRA_TYPE_CHECKINGboth OFF and ON.Refs #2305.