Skip to content
Merged
Prev Previous commit
Next Next commit
Guard against null triggeringProcessImageFileName from ProjFS
ProjFS managed API v2.1.0 uses Marshal.PtrToStringUni which returns null
for IntPtr.Zero (kernel operations with PID 0). The old C++/CLI wrapper
returned String.Empty. Null-coalesce to match old behavior in all three
callback sites (OnPlaceholderFileCreated, OnPlaceholderFolderCreated,
OnPlaceholderFileHydrated); ConcurrentDictionary does not accept null keys.

Co-authored-by: Michael Niksa <miniksa@microsoft.com>
Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
  • Loading branch information
tyrielv and miniksa committed May 1, 2026
commit c36bc2376a4c53541f6b270ff225d441dd15a115
10 changes: 7 additions & 3 deletions GVFS/GVFS.Virtualization/FileSystemCallbacks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -695,8 +695,12 @@ public void OnPlaceholderFileCreated(string relativePath, string sha, string tri
// Note: Because OnPlaceholderFileCreated is not synchronized on all platforms it is possible that GVFS will double count
// the creation of file placeholders if multiple requests for the same file are received at the same time on different
// threads.
//
// triggeringProcessImageFileName can be null when ProjFS reports a triggering process ID of 0 (e.g. kernel or
// system-level operations). The ProjFS managed API may pass null for the image file name in AOT builds.
// ConcurrentDictionary does not allow null keys, so fall back to a sentinel value.
this.filePlaceHolderCreationCount.AddOrUpdate(
triggeringProcessImageFileName,
triggeringProcessImageFileName ?? string.Empty,
(imageName) => { return new PlaceHolderCreateCounter(); },
(key, oldCount) => { oldCount.Increment(); return oldCount; });
}
Expand All @@ -711,7 +715,7 @@ public void OnPlaceholderFolderCreated(string relativePath, string triggeringPro
this.GitIndexProjection.OnPlaceholderFolderCreated(relativePath);

this.folderPlaceHolderCreationCount.AddOrUpdate(
triggeringProcessImageFileName,
triggeringProcessImageFileName ?? string.Empty,
(imageName) => { return new PlaceHolderCreateCounter(); },
(key, oldCount) => { oldCount.Increment(); return oldCount; });
}
Expand All @@ -724,7 +728,7 @@ public void OnPlaceholderFolderExpanded(string relativePath)
public void OnPlaceholderFileHydrated(string triggeringProcessImageFileName)
{
this.fileHydrationCount.AddOrUpdate(
triggeringProcessImageFileName,
triggeringProcessImageFileName ?? string.Empty,
(imageName) => { return new PlaceHolderCreateCounter(); },
(key, oldCount) => { oldCount.Increment(); return oldCount; });
}
Expand Down