From 9c8f5952032a705eb592ee4ab65c1b879ea0c864 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 27 Oct 2026 16:09:28 +0100 Subject: [PATCH] BUG/MINOR: mux_quic: fix stream elasticity dec on qcm_init() failure On qcm_init() early failure, QCC is freed via qcc_release(). This function always decrements reserved streams from the thread group pool when stream elasticity is active for frontend connections. This causes an issue as qcm_init() may fail before accounting the committed streams: this is the case for allocation failure. Thread group counter is thus invalid after the extra decrement and may cause an underflow and wrap. Fix this by moving pacing task allocation later in qcm_init() so that streams accounting is now performed before any failure path. This must be backported up to 3.4. --- src/mux_quic.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/mux_quic.c b/src/mux_quic.c index 94c4ea890..769b6eb68 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -4132,22 +4132,6 @@ static int qcm_init(struct connection *conn, struct proxy *prx, qcc->tx.buf_in_flight = 0; - if (qcc_is_pacing_active(conn)) { - quic_pacing_init(&qcc->tx.pacer, &conn->handle.qc->path->cc); - qcc->tx.paced_sent_ctr = 0; - - /* Initialize pacing_task. */ - qcc->pacing_task = task_new_here(); - if (!qcc->pacing_task) { - TRACE_ERROR("pacing task alloc failure", QMUX_EV_QCC_NEW); - goto err; - } - qcc->pacing_task->process = qcc_pacing_task; - qcc->pacing_task->context = qcc; - qcc->pacing_task->expire = TICK_ETERNITY; - qcc->pacing_task->state |= TASK_F_WANTS_TIME; - } - if (!conn_is_quic(conn)) { qcc->tx.qmux_buf = BUF_NULL; qcc->rx.qmux_buf = BUF_NULL; @@ -4176,6 +4160,22 @@ static int qcm_init(struct connection *conn, struct proxy *prx, } } + if (qcc_is_pacing_active(conn)) { + quic_pacing_init(&qcc->tx.pacer, &conn->handle.qc->path->cc); + qcc->tx.paced_sent_ctr = 0; + + /* Initialize pacing_task. */ + qcc->pacing_task = task_new_here(); + if (!qcc->pacing_task) { + TRACE_ERROR("pacing task alloc failure", QMUX_EV_QCC_NEW); + goto err; + } + qcc->pacing_task->process = qcc_pacing_task; + qcc->pacing_task->context = qcc; + qcc->pacing_task->expire = TICK_ETERNITY; + qcc->pacing_task->state |= TASK_F_WANTS_TIME; + } + qcc->wait_event.tasklet = tasklet_new(); if (!qcc->wait_event.tasklet) { TRACE_ERROR("tasklet alloc failure", QMUX_EV_QCC_NEW); -- 2.47.3