Summary
In src/moq-source.cpp, moq_source_start_consume now calls moq_origin_consume_announced and stores the returned task handle in ctx->consume_announced_task. The terminal callback on_broadcast_ready (broadcast <= 0) unconditionally clears ctx->consume_announced_task, and the success path (broadcast > 0) reads ctx->generation at callback time rather than validating against the generation the task was created for.
Problem
If a reconnect happens while an older consume-announced task is still winding down, a late terminal callback from that stale task can clear the newer task's handle in ctx->consume_announced_task, or (on the success path) attach a broadcast handle intended for an old generation to the current generation state.
Impact
Bounded: each task holds its own ctx reference (via subscription_ref), so there is no use-after-free. The only effect is that the newer wait loses its proactive moq_origin_consume_announced_close() on disconnect and instead resolves naturally when the origin is torn down; the existing refs timeout in moq_source_destroy still bounds teardown. The happy path is unaffected.
Proposed fix
Thread per-task state (task token + expected generation) through to on_broadcast_ready, and have the callback verify the callback still corresponds to the current task/generation before mutating ctx->consume_announced_task or ctx->consume. This likely also touches the similar generation-check pattern used in on_session_status and on_catalog for consistency.
Affected areas
src/moq-source.cpp: moq_source_start_consume, on_broadcast_ready, moq_source struct (task/generation bookkeeping)
Acceptance criteria
- A stale terminal callback from a closed/replaced consume-announced task cannot clear a newer
ctx->consume_announced_task handle.
- A stale success callback (broadcast > 0) cannot attach its handle to the wrong generation.
- No regression to the existing reconnect/teardown ref-counting and bounded-wait behavior.
References
Summary
In
src/moq-source.cpp,moq_source_start_consumenow callsmoq_origin_consume_announcedand stores the returned task handle inctx->consume_announced_task. The terminal callbackon_broadcast_ready(broadcast <= 0) unconditionally clearsctx->consume_announced_task, and the success path (broadcast > 0) readsctx->generationat callback time rather than validating against the generation the task was created for.Problem
If a reconnect happens while an older consume-announced task is still winding down, a late terminal callback from that stale task can clear the newer task's handle in
ctx->consume_announced_task, or (on the success path) attach a broadcast handle intended for an old generation to the current generation state.Impact
Bounded: each task holds its own
ctxreference (viasubscription_ref), so there is no use-after-free. The only effect is that the newer wait loses its proactivemoq_origin_consume_announced_close()on disconnect and instead resolves naturally when the origin is torn down; the existingrefstimeout inmoq_source_destroystill bounds teardown. The happy path is unaffected.Proposed fix
Thread per-task state (task token + expected generation) through to
on_broadcast_ready, and have the callback verify the callback still corresponds to the current task/generation before mutatingctx->consume_announced_taskorctx->consume. This likely also touches the similar generation-check pattern used inon_session_statusandon_catalogfor consistency.Affected areas
src/moq-source.cpp:moq_source_start_consume,on_broadcast_ready,moq_sourcestruct (task/generation bookkeeping)Acceptance criteria
ctx->consume_announced_taskhandle.References