Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

avoid NRE in MsQuicConnection ConnectAsync #56283

Merged
merged 7 commits into from
Jul 29, 2021
Merged

avoid NRE in MsQuicConnection ConnectAsync #56283

merged 7 commits into from
Jul 29, 2021

Conversation

wfurt
Copy link
Member

@wfurt wfurt commented Jul 26, 2021

This is recent regression caused by #55468.
When we fail faster than we can return ConnectTcs in ConnectAsync, it may be null and the return would fail.
So instead of setting it to null to prefer double cleanup I added Task.IsCompleted check.

fixes #56263
fixes #56454

@wfurt wfurt requested a review from a team July 26, 2021 04:53
@wfurt wfurt self-assigned this Jul 26, 2021
@ghost
Copy link

ghost commented Jul 26, 2021

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

This is recent regression caused by #55468.
When we fail faster than we can return ConnectTcs in ConnectAsync, it may be null and the return would fail. So instead of setting it to null to prefer double cleanup I added Task.IsCompleted` check.

fixes #56263

Author: wfurt
Assignees: wfurt
Labels:

area-System.Net.Quic

Milestone: -

state.ConnectTcs.SetException(ex);
state.ConnectTcs = null;
// This is opportunistic if we get exception and have ability to propagate it to caller.
state.ConnectTcs.TrySetException(ex);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the change I was hinting at when asking about the race condition.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I can do better fix. Instead of checking state of the task I can simply store TaskCompletionSource in ConnectAsync to local variable and return that. There is really no reason to drag it past Connect event.

@@ -234,15 +234,14 @@ private static uint HandleEventConnected(State state, ref ConnectionEvent connec

private static uint HandleEventShutdownInitiatedByTransport(State state, ref ConnectionEvent connectionEvent)
{
if (!state.Connected && state.ConnectTcs != null)
if (!state.Connected && state.ConnectTcs != null && !state.ConnectTcs.Task.IsCompleted)
{
Debug.Assert(state.Connection != null);
state.Connection = null;

uint hresult = connectionEvent.Data.ShutdownInitiatedByTransport.Status;
Exception ex = QuicExceptionHelpers.CreateExceptionForHResult(hresult, "Connection has been shutdown by transport.");
state.ConnectTcs!.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(ex));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be TrySetException as well?

@wfurt
Copy link
Member Author

wfurt commented Jul 27, 2021

I did different fix @stephentoub, can you please take another quic look. To avoid fighting over global state, I store the original tcs in local variable so it would never NRE. And then the state.ConnectTcs is set & cleared on successful connect or on failure. Looks simpler than trying to figure out state of Task.

Copy link
Member

@CarnaViire CarnaViire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit, otherwise LGTM

@wfurt wfurt merged commit 87769fb into dotnet:main Jul 29, 2021
@wfurt wfurt deleted the nre_56263 branch July 29, 2021 05:02
@karelz karelz added this to the 6.0.0 milestone Jul 29, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
4 participants