From 5980ac22d8679e8a15afc1c373fde210ae5d9dd5 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Tue, 4 May 2021 14:50:52 -0700 Subject: [PATCH] Release GCHandle in FSEventStreamContext release callback The callbacks are sometimes delivered even after the FSEventStream is disposed --- .../Common/src/Interop/OSX/Interop.EventStream.cs | 4 ++-- .../Interop/OSX/Interop.SystemConfiguration.cs | 4 ++-- .../src/System/IO/FileSystemWatcher.OSX.cs | 15 ++++++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libraries/Common/src/Interop/OSX/Interop.EventStream.cs b/src/libraries/Common/src/Interop/OSX/Interop.EventStream.cs index b596e8c7620fc0..9f32269e1b8e41 100644 --- a/src/libraries/Common/src/Interop/OSX/Interop.EventStream.cs +++ b/src/libraries/Common/src/Interop/OSX/Interop.EventStream.cs @@ -78,8 +78,8 @@ internal struct FSEventStreamContext { public CFIndex version; public IntPtr info; - public IntPtr retainFunc; - public IntPtr releaseFunc; + public IntPtr retain; + public IntPtr release; public IntPtr copyDescription; } diff --git a/src/libraries/Common/src/Interop/OSX/Interop.SystemConfiguration.cs b/src/libraries/Common/src/Interop/OSX/Interop.SystemConfiguration.cs index d19abc8bccefc5..5d9e896dd40248 100644 --- a/src/libraries/Common/src/Interop/OSX/Interop.SystemConfiguration.cs +++ b/src/libraries/Common/src/Interop/OSX/Interop.SystemConfiguration.cs @@ -19,8 +19,8 @@ internal struct SCDynamicStoreContext { public CFIndex version; public IntPtr info; - public IntPtr retainFunc; - public IntPtr releaseFunc; + public IntPtr retain; + public IntPtr release; public IntPtr copyDescription; } diff --git a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs index 2081e679cbc176..a976a9a1043a37 100644 --- a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs +++ b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.cs @@ -275,9 +275,6 @@ private void CleanupEventStream() StaticWatcherRunLoopManager.UnscheduleFromRunLoop(eventStream); eventStream.Dispose(); - - Debug.Assert(_gcHandle.IsAllocated); - _gcHandle.Free(); } } @@ -314,6 +311,7 @@ internal unsafe void Start(CancellationToken cancellationToken) Interop.EventStream.FSEventStreamContext context = default; context.info = GCHandle.ToIntPtr(_gcHandle); + context.release = (IntPtr)(delegate* unmanaged)&ReleaseCallback; // Create the event stream for the path and tell the stream to watch for file system events. SafeEventStreamHandle eventStream = Interop.EventStream.FSEventStreamCreate( @@ -336,7 +334,10 @@ internal unsafe void Start(CancellationToken cancellationToken) finally { if (cleanupGCHandle) + { + Debug.Assert(_gcHandle.Target is RunningInstance); _gcHandle.Free(); + } arrPaths?.Dispose(); path?.Dispose(); } @@ -373,6 +374,14 @@ internal unsafe void Start(CancellationToken cancellationToken) } } + [UnmanagedCallersOnly] + private static void ReleaseCallback(IntPtr clientCallBackInfo) + { + GCHandle gcHandle = GCHandle.FromIntPtr(clientCallBackInfo); + Debug.Assert(gcHandle.Target is RunningInstance); + gcHandle.Free(); + } + [UnmanagedCallersOnly] private static unsafe void FileSystemEventCallback( FSEventStreamRef streamRef,