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

Fix NullReferenceException in FileSystemWatcher on Windows during dispose #100766

Merged
merged 1 commit into from
Apr 18, 2024

Conversation

martincostello
Copy link
Member

@martincostello martincostello commented Apr 8, 2024

Fix NullReferenceException in FileSystemWatcher on Windows if two threads try and dispose the instance at the same time.

Found in a failing test while running the CI in a PR against the OpenTelemetry libraries for net8.0 on Windows: workflow logs

Failed OpenTelemetry.Instrumentation.AspNetCore.Tests.BasicTests.AddAspNetCoreInstrumentation_BadArgs [1 ms]
  Error Message:
   [Test Class Cleanup Failure (OpenTelemetry.Instrumentation.AspNetCore.Tests.BasicTests)]: System.NullReferenceException : Object reference not set to an instance of an object.
  Stack Trace:
     at System.IO.FileSystemWatcher.StopRaisingEvents()
   at System.IO.FileSystemWatcher.Dispose(Boolean disposing)
   at System.ComponentModel.Component.Dispose()
   at Microsoft.Extensions.FileProviders.Physical.PhysicalFilesWatcher.Dispose(Boolean disposing)
   at Microsoft.Extensions.FileProviders.PhysicalFileProvider.Dispose(Boolean disposing)
   at Microsoft.Extensions.FileProviders.PhysicalFileProvider.Dispose()
   at Microsoft.Extensions.Hosting.Internal.Host.<DisposeAsync>g__DisposeAsync|21_0(Object o)
   at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync()
   at Microsoft.Extensions.Hosting.Internal.Host.Dispose()
   at Microsoft.AspNetCore.Mvc.Testing.DeferredHostBuilder.DeferredHost.Dispose()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.DisposeAsync()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.DisposeAsync()
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.Dispose(Boolean disposing)
   at Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory`1.Dispose()

Copy link
Contributor

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

@stephentoub
Copy link
Member

if two threads try and dispose the instance at the same time

It's not thread-safe. If two threads are calling Dispose concurrently, that's a bug in the consumer.

@martincostello
Copy link
Member Author

martincostello commented Apr 8, 2024

Sure, but trying to find where the exception was coming from it looks like both the Linux and macOS implementations of StopRaisingEvents() guard against the state changing to a degree:

CancellationTokenSource? token = _cancellation;
if (token != null)
{
_cancellation = null;
token.Cancel();
token.Dispose();
}
}

var cts = _cancellation;
if (cts != null)
{
_cancellation = null;
cts.Cancel();
}

Windows seems to be the odd-one-out here, so seemed reasonable to me to add the null guard.

I haven't looked into OTel's tests as to why it's happening - it could be an issue with their tests, it could be something in xunit as it appears to happen during test class cleanup.

@martincostello
Copy link
Member Author

Looks like a standard xunit IClassFixture<T> usage, which itself is copied from some old samples in aspnetcore.

@stephentoub
Copy link
Member

both the Linux and macOS implementations of StopRaisingEvents() guard against the state changing to a degree:

If the goal is consistency, then it'd be better to do:

SafeFileHandle? handle = _directoryHandle;
if (handle is not null)
{
    _directoryHandle = null;
    handle.Dispose();
}

That won't address other problems with this instance being erroneously used concurrently, though.

@martincostello
Copy link
Member Author

Sure, I'll refactor that then. I went with ? as it was the smallest change.

Fix `NullReferenceException` in `FileSystemWatcher` on Windows if two threads try and dispose the instance at the same time.
@jozkee jozkee merged commit 7deec69 into dotnet:main Apr 18, 2024
85 of 87 checks passed
@martincostello martincostello deleted the patch-1 branch April 18, 2024 22:38
matouskozak pushed a commit to matouskozak/runtime that referenced this pull request Apr 30, 2024
Fix `NullReferenceException` in `FileSystemWatcher` on Windows if two threads try and dispose the instance at the same time.
@github-actions github-actions bot locked and limited conversation to collaborators May 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants