Description
I grabbed a dump during the long delay where nothing is happening and the test is waiting for it's timeout. The dump has one
QuicConnection
rooted still. Which, when you track the reference down, is fromQuicConnection._connectedTcs._keepAlive
. So basically theQuicConnection
is rooting itself. Normally this would be cleaned up by awaiting the task returned viaQuicConnection.FinishHandshakeAsync
orQuicConnection.FinishConnectAsync
so I tracked down which method the rooted connection came from, and it was fromFinishHandshakeAsync
.
And the reason the ValueTask returned from
FinishHandshakeAsync
isn't awaited (thus freeing the GCHandle) is because the method throws which keeps the GCHandle alive forever in this case.
The reason the test worked before was because the TCS wasn't disposed before @stephentoub's change which meant there was a 10 second timeout that would eventually cleanup the ValueTask and thus the GCHandle.
So properly disposing the TCS exposed a bug in QuicConnection.
Originally posted by @BrennanConroy in #48558 (comment)