You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found while running #550's Part 1. Filed rather than left as an aside inside that issue's comments, per AGENTS.md — "File, don't fold. An aside inside a closed issue lapses unless it gets its own issue."
The finding
#550's Part 1 produced a table of 27 cancellation entry points and measured their guarantees on a five-point scale (G0 nothing … G4 no callback still running). Four of those rows were reproduced by standalone probe programs, and two of the reproductions were sharp enough to become defects in their own right:
Those probe programs are gone. They lived in a lane scratchpad and were removed with the worktree. So the guarantees they proved are now recorded as prose on #550 and asserted by nothing that runs.
Why that matters here specifically
The whole point of #550's scale is the distinction between "no further callback will be scheduled" (G1/G2) and "no further callback will start" (G3). A caller who reads a G2 verb as G3 and frees the receiver on the next statement has a use-after-free — and docs/spec/concurrency_and_lifetimes.md:164 says the rules there "encode recent fixes to real deadlocks and use-after-frees", so this is a class of bug this repository has already shipped and fixed at least once.
A guarantee that nothing asserts is a guarantee that can regress silently. That is AGENTS.md's "verify rather than assert" applied to the concurrency contract itself.
Verification status: weak, and labelled as weak
Measured on master @ 0e3b8823:
$ grep -rn "cancelPending" tests/ | wc -l
38
38 call sites across 12 test files. So the verbs are exercised a great deal — this is emphatically not "cancellation is untested."
What I could not establish is whether any test asserts the strength of the guarantee rather than its effect. My probe for that was crude — searching each file for an assertion that a counter stayed at zero near a cancelPending — and it found none in any of the twelve:
That heuristic is not good enough to conclude on. It matches only a few spellings of "this did not happen", and a test could assert the same property through a Catch2 matcher, a drained-queue check, or a scope-exit assertion it would never see. Do not treat "zero-assertions=0" as a measurement — treat it as the reason someone should look properly.
I did not: read any of the twelve test files, run the suite, or attempt to reconstruct the deleted probes.
What would resolve it
Audit the twelve files properly and establish whether any existing test distinguishes G2 from G3. If one does, this issue shrinks to "land the remaining probes."
Found while running #550's Part 1. Filed rather than left as an aside inside that issue's comments, per AGENTS.md — "File, don't fold. An aside inside a closed issue lapses unless it gets its own issue."
The finding
#550's Part 1 produced a table of 27 cancellation entry points and measured their guarantees on a five-point scale (G0 nothing … G4 no callback still running). Four of those rows were reproduced by standalone probe programs, and two of the reproductions were sharp enough to become defects in their own right:
SynchronousBackendAdapter::cancelPendingdoes not cancel the completions the adapter itself produced. Measured: aftercancelPending(BridgeDestroyedError)the bind's.thenfired with a success value (okRan=1 errRan=0).TimeoutScheduler::cancel()returns while an already-firing callback is still executing.Those probe programs are gone. They lived in a lane scratchpad and were removed with the worktree. So the guarantees they proved are now recorded as prose on #550 and asserted by nothing that runs.
Why that matters here specifically
The whole point of #550's scale is the distinction between "no further callback will be scheduled" (G1/G2) and "no further callback will start" (G3). A caller who reads a G2 verb as G3 and frees the receiver on the next statement has a use-after-free — and
docs/spec/concurrency_and_lifetimes.md:164says the rules there "encode recent fixes to real deadlocks and use-after-frees", so this is a class of bug this repository has already shipped and fixed at least once.A guarantee that nothing asserts is a guarantee that can regress silently. That is AGENTS.md's "verify rather than assert" applied to the concurrency contract itself.
Verification status: weak, and labelled as weak
Measured on
master@0e3b8823:38 call sites across 12 test files. So the verbs are exercised a great deal — this is emphatically not "cancellation is untested."
What I could not establish is whether any test asserts the strength of the guarantee rather than its effect. My probe for that was crude — searching each file for an assertion that a counter stayed at zero near a
cancelPending— and it found none in any of the twelve:That heuristic is not good enough to conclude on. It matches only a few spellings of "this did not happen", and a test could assert the same property through a Catch2 matcher, a drained-queue check, or a scope-exit assertion it would never see. Do not treat "zero-assertions=0" as a measurement — treat it as the reason someone should look properly.
I did not: read any of the twelve test files, run the suite, or attempt to reconstruct the deleted probes.
What would resolve it
tests/test_cancellation_policy.cpp— one case per reproduced row of research: write down the real cancellation policy, then test whether stdexec (or std::stop_token, or strand-confinement) removes any of the 54 mutexes #550's table, asserting the G-level, not just that an error arrived. research: write down the real cancellation policy, then test whether stdexec (or std::stop_token, or strand-confinement) removes any of the 54 mutexes #550's second comment proposes exactly this as a regression baseline for its Part 2.errRan == 1 && okRan == 0, so it fails today and passes once core: SynchronousBackendAdapter::cancelPending does not cancel the completions the adapter itself produced #619 is fixed. A case that merely asserts "something settled" would pass in both worlds and is not evidence.The probes cannot be recovered, so step 2 means rewriting them from the table on #550, which is the durable record that survived.
What would change the verdict
Related
SynchronousBackendAdapter, which is what makes core: SynchronousBackendAdapter::cancelPending does not cancel the completions the adapter itself produced #619's path the default.