]> Cypherpunks repositories - gostls13.git/commitdiff
internal/poll: fix race in Close
authorqmuntal <quimmuntal@gmail.com>
Tue, 8 Apr 2025 13:31:02 +0000 (15:31 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Wed, 9 Apr 2025 20:07:09 +0000 (13:07 -0700)
There is a potential race between a concurrent call to FD.initIO, which
calls FD.pd.init, and a call to FD.Close, which calls FD.pd.evict.

This is solved by calling FD.initIO in FD.Close, as that will block
until the concurrent FD.initIO has completed. Note that FD.initIO is
no-op if first called from here.

The race window is so small that it is not possible to write a test
that triggers it.

Change-Id: Ie2f2818e746b9d626fe3b9eb6b8ff967c81ef863
Reviewed-on: https://go-review.googlesource.com/c/go/+/663815
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
src/internal/poll/fd_windows.go

index 6660bcd9594e2fa40f89857725e6efe398758beb..99891de76362ef1e96920d1ab8a23a6d6108bd04 100644 (file)
@@ -336,6 +336,10 @@ func (fd *FD) initIO() error {
                return nil
        }
        fd.initIOOnce.Do(func() {
+               if fd.closing() {
+                       // Closing, nothing to do.
+                       return
+               }
                // The runtime poller will ignore I/O completion
                // notifications not initiated by this package,
                // so it is safe to add handles owned by the caller.
@@ -434,6 +438,12 @@ func (fd *FD) Close() error {
        if !fd.fdmu.increfAndClose() {
                return errClosing(fd.isFile)
        }
+       // There is a potential race between a concurrent call to fd.initIO,
+       // which calls fd.pd.init, and the call to fd.pd.evict below.
+       // This is solved by calling fd.initIO ourselves, which will
+       // block until the concurrent fd.initIO has completed. Note
+       // that fd.initIO is no-op if first called from here.
+       fd.initIO()
        if fd.kind == kindPipe {
                syscall.CancelIoEx(fd.Sysfd, nil)
        }