Open
Conversation
Add a unit-test-only NetworkState hook that reports whether cleanup can still cancel a request while the client's HTTP completion callback is running. Add TestHttpCallCompletionCallbackIsNotCleanupCancelable in GlobalTests to capture the current behavior with a mocked HTTP call. The test asserts that the request should no longer be cleanup-cancelable once the client callback is executing, which reproduces the lifetime bug that will be addressed in a follow-up fix commit.
Track active HTTP performs by HttpPerformContext and add an explicit handoff state for the client-owned XAsyncBlock during cleanup and completion. The cleanup path now snapshots requests under the NetworkState mutex, marks cancel-in-flight requests, and issues XAsyncCancel outside the lock. The completion path waits until cleanup finishes cancel propagation before publishing callback ownership and completing the client async block. This preserves the repro commit as the first commit on the branch and records the fix as the second commit.
e9d7154 to
2e5386e
Compare
There was a problem hiding this comment.
Pull request overview
This PR addresses issue #956 by preventing HCCleanupAsync from interacting with a client-owned XAsyncBlock after the HTTP completion path has taken ownership of the callback (and the client may legally free that block). The change adds explicit state coordination between cleanup-driven cancellation and perform completion to eliminate a potential use-after-free race.
Changes:
- Track active HTTP performs via
HttpPerformContext*rather than raw clientXAsyncBlock*. - Add an explicit atomic handoff state (
CleanupMayCancel/CleanupCancelInFlight/CallbackStarted) to coordinate cleanup cancellation vs. completion callback ownership. - Snapshot active HTTP requests under the
NetworkStatemutex and issueXAsyncCanceloutside the lock; add a unit test regression for the callback ownership guarantee.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
Tests/UnitTests/Tests/GlobalTests.cpp |
Adds a regression test asserting cleanup cannot treat an HTTP request as cancelable once the completion callback begins. |
Source/Global/NetworkState.h |
Changes the active HTTP request tracking set to store perform contexts; exposes a unit-test-only query API. |
Source/Global/NetworkState.cpp |
Implements the perform-context tracking and the cleanup/completion handoff state machine; adjusts cleanup cancellation to operate on snapshotted contexts. |
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 #956
Summary
This change tightens the handoff between HTTP cleanup and HTTP completion so cleanup no longer touches the client-owned
XAsyncBlockafter the completion path has claimed callback ownership.Problem
Cleanup and completion can overlap on the same HTTP perform. In that window, cleanup can still treat the request as cancelable through the client-owned
XAsyncBlockeven after the completion callback has started. The API documentation allows the callback to free thatXAsyncBlock, which can turn a laterXAsyncCancelinto a use-after-free.What changed
HttpPerformContextinstead of raw clientXAsyncBlockpointers.NetworkStatemutex and issueXAsyncCanceloutside the lock.Validation
Summary: Total=83, Passed=83, Failed=0, Blocked=0, Not Run=0, Skipped=0.Notes
This branch is intentionally split into two commits: the repro commit and the fix commit.