Found in the pre-4.0 audit (follow-up to #360/#361).
ResultAsyncEnumerableParallelProcessor<TInput, TOutput>.ExecuteAsync, unbounded path: if the consumer breaks out of await foreach early, iterator disposal runs the finally, which awaits ALL in-flight tasks — nothing cancels the processor's linked CTS on abandonment — and the bare catch { } then discards every failure.
Failure scenario: consume 1 result of a 10,000-item unbounded run and break → the await foreach exit blocks until every started task naturally completes (minutes, if the delegate is slow), and any exceptions thrown by those tasks silently vanish.
Its void twin has the opposite bug: AsyncEnumerableParallelProcessor.ExecuteAsync's finally has no catch, so when source enumeration throws and an in-flight task later faults, the finally's Task.WhenAll throw REPLACES the original source exception — the user sees the wrong root cause.
Proposal: cancel the internal CTS when the result iterator is disposed before completion (abandonment = cancellation), bound the drain wait, and unify the two paths' exception policy (preserve the in-flight/original exception, don't swallow or mask).
Found in the pre-4.0 audit (follow-up to #360/#361).
ResultAsyncEnumerableParallelProcessor<TInput, TOutput>.ExecuteAsync, unbounded path: if the consumerbreaks out ofawait foreachearly, iterator disposal runs thefinally, which awaits ALL in-flight tasks — nothing cancels the processor's linked CTS on abandonment — and the barecatch { }then discards every failure.Failure scenario: consume 1 result of a 10,000-item unbounded run and
break→ theawait foreachexit blocks until every started task naturally completes (minutes, if the delegate is slow), and any exceptions thrown by those tasks silently vanish.Its void twin has the opposite bug:
AsyncEnumerableParallelProcessor.ExecuteAsync'sfinallyhas no catch, so when source enumeration throws and an in-flight task later faults, thefinally'sTask.WhenAllthrow REPLACES the original source exception — the user sees the wrong root cause.Proposal: cancel the internal CTS when the result iterator is disposed before completion (abandonment = cancellation), bound the drain wait, and unify the two paths' exception policy (preserve the in-flight/original exception, don't swallow or mask).