From e0241fa3a8f64f77caf3cb38e9ce0973c88571c7 Mon Sep 17 00:00:00 2001 From: Guillaume Hetier Date: Fri, 21 Aug 2026 14:01:32 -0700 Subject: [PATCH 1/3] Flush receive batch before path lookup Avoid calling QuicConnGetPathForPacket while the receive batch still holds a pointer into the path array. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03ce1c1f-9bb3-4a56-be65-d7f4d3fb46eb --- src/core/connection.c | 25 +++++++++++++++---------- src/core/path.c | 16 ++++++++++++++++ src/core/path.h | 7 +++++++ 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/core/connection.c b/src/core/connection.c index 2235a32914..ccb3c88189 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -5769,15 +5769,9 @@ QuicConnRecvDatagrams( CXPLAT_DBG_ASSERT(Packet->ReleaseDeferred == IsDeferred); Packet->ReleaseDeferred = FALSE; - QUIC_PATH* DatagramPath = QuicConnGetPathForPacket(Connection, Packet); - if (DatagramPath == NULL) { - QuicPacketLogDrop(Connection, Packet, "Max paths already tracked"); - goto Drop; - } - - CxPlatUpdateRoute(&DatagramPath->Route, Packet->Route); - - if (DatagramPath != CurrentPath) { + if (CurrentPath == NULL) { + CurrentPath = QuicConnGetPathForPacket(Connection, Packet); + } else if (!QuicPathMatchPacket(CurrentPath, Packet)) { if (BatchCount != 0) { // // This datagram is from a different path than the current @@ -5793,9 +5787,20 @@ QuicConnRecvDatagrams( &RecvState); BatchCount = 0; } - CurrentPath = DatagramPath; + // + // Path lookup can modify the path array, so only do it after the + // current batch no longer holds a path pointer. + // + CurrentPath = QuicConnGetPathForPacket(Connection, Packet); + } + + if (CurrentPath == NULL) { + QuicPacketLogDrop(Connection, Packet, "Max paths already tracked"); + goto Drop; } + CxPlatUpdateRoute(&CurrentPath->Route, Packet->Route); + if (!IsDeferred) { Connection->Stats.Recv.TotalBytes += Packet->BufferLength; if (Connection->Stats.Handshake.HandshakeHopLimitTTL == 0) { diff --git a/src/core/path.c b/src/core/path.c index 563f8d30d1..405f646afe 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -257,6 +257,22 @@ QuicConnGetPathByID( return NULL; } +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathMatchPacket( + _In_ const QUIC_PATH* Path, + _In_ const QUIC_RX_PACKET* Packet + ) +{ + return + QuicAddrCompare( + &Packet->Route->LocalAddress, + &Path->Route.LocalAddress) && + QuicAddrCompare( + &Packet->Route->RemoteAddress, + &Path->Route.RemoteAddress); +} + _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ QUIC_PATH* diff --git a/src/core/path.h b/src/core/path.h index 4dafd7d53e..2024c31f10 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -333,6 +333,13 @@ QuicConnGetPathByID( _Out_ uint8_t* Index ); +_IRQL_requires_max_(PASSIVE_LEVEL) +BOOLEAN +QuicPathMatchPacket( + _In_ const QUIC_PATH* Path, + _In_ const QUIC_RX_PACKET* Packet + ); + _IRQL_requires_max_(PASSIVE_LEVEL) _Ret_maybenull_ QUIC_PATH* From 7aac8118ea19de8955706061624249cb75d66c65 Mon Sep 17 00:00:00 2001 From: Guillaume Hetier Date: Thu, 27 Aug 2026 12:41:17 -0700 Subject: [PATCH 2/3] Reuse path packet matching helper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03ce1c1f-9bb3-4a56-be65-d7f4d3fb46eb --- src/core/path.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/path.c b/src/core/path.c index 405f646afe..c302f377ea 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -283,12 +283,7 @@ QuicConnGetPathForPacket( { QUIC_PATH_SET* PathSet = &Connection->Paths; for (uint8_t i = 0; i < PathSet->Count; ++i) { - if (!QuicAddrCompare( - &Packet->Route->LocalAddress, - &PathSet->Paths[i].Route.LocalAddress) || - !QuicAddrCompare( - &Packet->Route->RemoteAddress, - &PathSet->Paths[i].Route.RemoteAddress)) { + if (!QuicPathMatchPacket(&PathSet->Paths[i], Packet)) { if (!Connection->State.HandshakeConfirmed) { // // Ignore packets on any other paths until connected/confirmed. From 7e5c6325ce18d154648aca04806a00be2a5b3150 Mon Sep 17 00:00:00 2001 From: Guillaume Hetier Date: Thu, 27 Aug 2026 15:14:40 -0700 Subject: [PATCH 3/3] Remove redundant current path assertion Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 03ce1c1f-9bb3-4a56-be65-d7f4d3fb46eb --- src/core/connection.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/connection.c b/src/core/connection.c index ccb3c88189..9964f1e3cd 100644 --- a/src/core/connection.c +++ b/src/core/connection.c @@ -5777,7 +5777,6 @@ QuicConnRecvDatagrams( // This datagram is from a different path than the current // batch. Flush the current batch before continuing. // - CXPLAT_DBG_ASSERT(CurrentPath != NULL); QuicConnRecvDatagramBatch( Connection, CurrentPath,