fix use-after-free in inplace_stop_source::request_stop() - #2303
Open
eklavya072 wants to merge 1 commit into
Open
eklavya072 wants to merge 1 commit into
eklavya072 wants to merge 1 commit into
Conversation
If a stop callback destroys the stop source (for example when it completes a when_all and the receiver destroys the operation state), request_stop() still calls __lock_() and stores to __state_ on the freed object. Make the destructor work like __remove_callback_. On the notifying thread it sets a flag that lives on request_stop()'s stack, so request_stop() returns without touching *this again. On any other thread it waits until request_stop() has finished. Sources that never had stop requested skip all of this. Fixes NVIDIA#1889
eklavya072
force-pushed
the
fix/inplace-stop-source-lifetime
branch
from
October 6, 2026 07:31
dbb74ae to
5cc004a
Compare
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.
Fixes #1889.
When a stop callback destroys the
inplace_stop_sourceit is registered with (which is whatwhen_alldoes when its last child completes and the receiver tears down the op-state),request_stop()keeps using the freed source after the callback returns. It calls__lock_()and later stores to__state_. ASan on main:Following @RobertLeahy's suggestion in the issue,
~inplace_stop_source()now handles this the same way__remove_callback_handles callbacks:request_stop()'s stack, andrequest_stop()returns without touching*thisagain.request_stop()is done with the source.Tests:
a stop callback can destroy the inplace_stop_sourcedestroys the source from a callback while another callback is still registered.inplace_stop_source destructor waits for request_stop on another threaddestroys it from another thread whilerequest_stop()is still running.The workaround from #1851 can probably be reverted once this is in, I left that for a separate PR. The same code is also in cudax's
stop_token.cuhin CCCL, I can send the same change there too.