Skip to content

Fix access of a Disposed cancellation token source.#63131

Merged
CyrusNajmabadi merged 4 commits intodotnet:mainfrom
CyrusNajmabadi:ctsDispose
Aug 2, 2022
Merged

Fix access of a Disposed cancellation token source.#63131
CyrusNajmabadi merged 4 commits intodotnet:mainfrom
CyrusNajmabadi:ctsDispose

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

No description provided.

@CyrusNajmabadi CyrusNajmabadi requested a review from dibarbet August 2, 2022 16:28
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner August 2, 2022 16:28
@ghost ghost added the Area-IDE label Aug 2, 2022
async Task<Solution> ComputePrimaryBranchAsync(CancellationToken cancellationToken)
{
var solution = await _disconnectedSolutionTask.ConfigureAwait(false);
return await updatePrimaryBranchAsync(solution, _cancellationTokenSource.Token).ConfigureAwait(false);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this would could absolutely start at some arbitrary point in the future, and definitely after a point that hte cts had been cancelled/disposed. accessing .Token off of a Disposed cts will throw an exception. If _disconnectedSolutionTask was complete, then that could happen synchronously here inside TryKickOffPrimaryBranchWork_NoLock which is called in a method which must run to completion to setup state properly.

THat said... i also have a feeling the synchronous case cannot be hit, because we shouldn't be able to observe a cancelled token source synchronously since we're in the same lock that is used to cancel the cts in the first place.

return ImmutableArray<Task>.Empty;

_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❓ why do we need to dispose of the CTS here? Cancel being called should be sufficient, and it can be cleaned up with garbage collection as needed while safely passing a cancelled token around.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's a good question. GEnerally speaking, it means:

  1. we're a good cleanup citizen. We're not holding onto things longer than necessary.
  2. we're also representing an invariant that this type wants to convey. when the ref count of this goes down, the CTS should be entirely finished with that at that point, and any accesses from that point on of _cts.Token should throw because it is a bug. This helps us have stronger invariants, which is always preferred in potentially racey code.

If we don't have this we actually risk doing bad things later and not catching it, would could lead to much harder to find issues.

Copy link
Copy Markdown
Contributor

@ryzngard ryzngard left a comment

Choose a reason for hiding this comment

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

Change is as described and seems reasonable, although more complex than I would have thought. Added a question about a different approach but going to sign off

@CyrusNajmabadi CyrusNajmabadi merged commit e3724d0 into dotnet:main Aug 2, 2022
@ghost ghost added this to the Next milestone Aug 2, 2022
@CyrusNajmabadi CyrusNajmabadi deleted the ctsDispose branch August 2, 2022 19:54
@dibarbet dibarbet modified the milestones: Next, 17.4 P2 Sep 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants