Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit fb1177a

Browse files
authored
Fix assert race condition in CurlResponseMessage (#28332)
If cancellation is requested between the earlier check in the method and the call to Register, Register will return a default registration, and then the callback will end up seeing a default token rather than the original token. That will not only trigger the assert we've been seeing, but will also result in the wrong token being stored into the task.
1 parent 9e8d443 commit fb1177a

File tree

1 file changed

+6
-4
lines changed

1 file changed

+6
-4
lines changed

src/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationT
332332
// the cancellation token. Dispose on the registration won't return until the action
333333
// associated with the registration has completed, but if that action is currently
334334
// executing and is blocked on the lock that's held while calling Dispose... deadlock.
335-
var crs = new CancelableReadState(destination, this);
335+
var crs = new CancelableReadState(destination, this, cancellationToken);
336336
crs._registration = cancellationToken.Register(s1 =>
337337
{
338338
((CancelableReadState)s1)._stream.EventSourceTrace("Cancellation invoked. Queueing work item to cancel read state");
@@ -341,11 +341,11 @@ public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationT
341341
var crsRef = (CancelableReadState)s2;
342342
lock (crsRef._stream._lockObject)
343343
{
344-
Debug.Assert(crsRef._registration.Token.IsCancellationRequested, "We should only be here if cancellation was requested.");
344+
Debug.Assert(crsRef._token.IsCancellationRequested, "We should only be here if cancellation was requested.");
345345
if (crsRef._stream._pendingReadRequest == crsRef)
346346
{
347347
crsRef._stream.EventSourceTrace("Canceling");
348-
crsRef.TrySetCanceled(crsRef._registration.Token);
348+
crsRef.TrySetCanceled(crsRef._token);
349349
crsRef._stream.ClearPendingReadRequest();
350350
}
351351
}
@@ -516,11 +516,13 @@ internal ReadState(Memory<byte> buffer) : base(TaskCreationOptions.RunContinuat
516516
private sealed class CancelableReadState : ReadState
517517
{
518518
internal readonly CurlResponseStream _stream;
519+
internal readonly CancellationToken _token;
519520
internal CancellationTokenRegistration _registration;
520521

521-
internal CancelableReadState(Memory<byte> buffer, CurlResponseStream responseStream) : base(buffer)
522+
internal CancelableReadState(Memory<byte> buffer, CurlResponseStream responseStream, CancellationToken cancellationToken) : base(buffer)
522523
{
523524
_stream = responseStream;
525+
_token = cancellationToken;
524526
}
525527
}
526528
}

0 commit comments

Comments
 (0)