Skip to content

Using of CancellationToken in RemoteJSDataStreamΒ #50676

@leeriorio

Description

@leeriorio

I analyzed the source code of ASP.NET Core v6.0.18 using a Svace static analyzer. He found an error of category HANDLE_LEAK with the following message

CancellationTokenSource.CreateLinkedTokenSource(a, b) is not disposed at the end of the function

in method GetLinkedCancellationToken(). Here's a source

private static CancellationToken GetLinkedCancellationToken(CancellationToken a, CancellationToken b)
{
if (a.CanBeCanceled && b.CanBeCanceled)
{
return CancellationTokenSource.CreateLinkedTokenSource(a, b).Token;
}
else if (a.CanBeCanceled)
{
return a;
}
return b;
}

First of all, its useful to note, that method CancellationTokenSource.CreateLinkedTokenSource() (link below) already has its own all necessary checks that are implemented in the method above

https://github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/System/Threading/CancellationTokenSource.cs#L748

Moreover, calling CreateLinkedTokenSource() actually creates instance of TokenSource, which can be disposed

Proposed update

This method is applied only twice in this class: in methods

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var linkedCancellationToken = GetLinkedCancellationToken(_streamCancellationToken, cancellationToken);
return await _pipeReaderStream.ReadAsync(buffer.AsMemory(offset, count), linkedCancellationToken);
}

and

public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
var linkedCancellationToken = GetLinkedCancellationToken(_streamCancellationToken, cancellationToken);
return await _pipeReaderStream.ReadAsync(buffer, linkedCancellationToken);
}

and I think, these methods can be improved with using using construction and removing GetLinkedCancellationToken() like this:

public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
    using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(_streamCancellationToken, cancellationToken).Token;
    return await _pipeReaderStream.ReadAsync(buffer.AsMemory(offset, count), linkedCancellationToken);
}	
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
    using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(_streamCancellationToken, cancellationToken).Token;
    return await _pipeReaderStream.ReadAsync(buffer, linkedCancellationToken);
}

Found by Linux Verification Center (linuxtesting.org) with SVACE.
Reporter: Aleksey Kolosov ([email protected]).
Organization: [email protected]

Metadata

Metadata

Assignees

No one assigned

    Labels

    Pillar: Technical DebtPriority:2Work that is important, but not critical for the releasearea-blazorIncludes: Blazor, Razor ComponentsbugThis issue describes a behavior which is not expected - a bug.help candidateIndicates that the issues may be a good fit for community to help with. Requires work from eng. team

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions