From 5acfdc196a28e905f69348ba0b5c50714492ba26 Mon Sep 17 00:00:00 2001 From: Robert Fratto Date: Wed, 20 Jul 2022 23:06:40 -0400 Subject: [PATCH] windows: protect access to isClosed with mutex (#454) isClosed may be read and modified concurrently if the Windows Watcher is closed at the same time as a new entry being added. This change protects isClosed to prevent race conditions. The order of fields for the Windows Watcher have been rearranged to group fields protected by the mutex together. --- windows.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/windows.go b/windows.go index 02ce7de..7ff7009 100644 --- a/windows.go +++ b/windows.go @@ -21,14 +21,16 @@ import ( // Watcher watches a set of files, delivering events to a channel. type Watcher struct { - Events chan Event - Errors chan error - isClosed bool // Set to true when Close() is first called - mu sync.Mutex // Map access - port syscall.Handle // Handle to completion port - watches watchMap // Map of watches (key: i-number) - input chan *input // Inputs to the reader are sent on this channel - quit chan chan<- error + Events chan Event + Errors chan error + + port syscall.Handle // Handle to completion port + input chan *input // Inputs to the reader are sent on this channel + quit chan chan<- error + + mu sync.Mutex // Protects access to watches, isClosed + watches watchMap // Map of watches (key: i-number) + isClosed bool // Set to true when Close() is first called } // NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. @@ -51,6 +53,9 @@ func NewWatcher() (*Watcher, error) { // Close removes all watches and closes the events channel. func (w *Watcher) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + if w.isClosed { return nil } @@ -67,9 +72,12 @@ func (w *Watcher) Close() error { // Add starts watching the named file or directory (non-recursively). func (w *Watcher) Add(name string) error { + w.mu.Lock() if w.isClosed { return errors.New("watcher already closed") } + w.mu.Unlock() + in := &input{ op: opAddWatch, path: filepath.Clean(name), -- 2.50.1