Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

FileSystemWatcher on macOS raises no Error when FSEvents drops events: the flags arrive on the watched folder's own path, which is skipped first

オープン 初心者向け
#136,577 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
76/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
csharp, macos

調査の方向性

src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.csを読み、特にルートパスのスキップとShouldRescanOccurの呼び出し付近にあるProcessEventsを確認してください。macOSで、提供されている大量削除用コンソールアプリを使って再現し、取りこぼされたFSEventsによってwatcherのErrorイベントが発生するか確認してください。ルートパスのイベントに取りこぼしを示すフラグが含まれている場合にエラーとして報告され、その処理順序を対象とする回帰テストがあることを完了条件とします。

索引モデルが issue の本文から書いたものです。

説明

area-System.IO untriaged
Description

On macOS, when more changes arrive at once than FSEvents queues, FSEvents drops events and says so with one event flagged kFSEventStreamEventFlagMustScanSubDirs | kFSEventStreamEventFlagUserDropped (0x3). That event's path is the watched folder itself.

ProcessEvents in FileSystemWatcher.OSX.cs skips every event on the watched folder's own path ("Match Windows and don't notify us about changes to the Root folder") before it calls ShouldRescanOccur. So the dropped-events flags never reach the Error event. The watcher loses changes silently, and its consumer can't tell it should rescan.

Reproduction Steps

A net10.0/net11.0 console app:

using System.Collections.Concurrent;

int count = args.Length > 0 ? int.Parse(args[0]) : 1000;
string folder = Directory.CreateTempSubdirectory("fsw-burst-").FullName;
for (int i = 0; i < count; i++)
{
    File.WriteAllText(Path.Combine(folder, $"F{i}.txt"), "x");
}
Thread.Sleep(1000);

ConcurrentDictionary<string, bool> deleted = new();
int errors = 0;
using FileSystemWatcher watcher = new(folder);
watcher.Deleted += (_, e) => deleted[e.FullPath] = true;
watcher.Error += (_, e) => { Interlocked.Increment(ref errors); Console.WriteLine($"Error: {e.GetException().Message}"); };
watcher.EnableRaisingEvents = true;
Thread.Sleep(1000);

Parallel.For(0, count, i => File.Delete(Path.Combine(folder, $"F{i}.txt")));
Thread.Sleep(5000);
Console.WriteLine($"{Environment.Version}: {count} files deleted, {deleted.Count} Deleted events, {errors} Error events");
Directory.Delete(folder, true);

Output on macOS 27.0.1, Apple Silicon, three runs on each runtime:

10.0.14: 1000 files deleted, 467 Deleted events, 0 Error events
10.0.14: 1000 files deleted, 544 Deleted events, 0 Error events
10.0.14: 1000 files deleted, 488 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 466 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 722 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 1000 Deleted events, 0 Error events

A raw FSEvents stream, created with the flags the watcher uses (FileEvents, NoDefer, WatchRoot; latency 0) and watching the same burst, got 460 events: 459 file removals and one event on the watched folder's own path with flags 0x3. The same happens with IncludeSubdirectories = true and the files in a subfolder: the flagged event is still on the watched folder's path.

Expected behavior

Either a Deleted event for every file, or an Error event saying events were lost.

Actual behavior

About half the deletions are reported, with no Error event.

Regression?

Not known.

Known Workarounds

Treat a burst of changes as possibly lossy, and list again the folders it touched.

Configuration

macOS 27.0.1 (Apple Silicon), .NET 10.0.14 and 11.0.0-rc.3.26522.148.

Other information

Calling ShouldRescanOccur before the root-path skip would fix it. #130637 changes the exception this path raises to InternalBufferOverflowException. Its test reaches the path through a mount in a subfolder, so it doesn't hit this ordering.

主要言語
C#
スター
18.4k
フォーク
5.8k
平均マージ
2日 16時間
マージ済み PR(30日)
631

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

dotnet/runtime のほかの issue

dotnet/runtime の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。