]> Cypherpunks repositories - gostls13.git/commitdiff
internal/poll: do not call SetFileCompletionNotificationModes if it is broken
authorAlex Brainman <alex.brainman@gmail.com>
Wed, 11 Oct 2017 07:15:25 +0000 (18:15 +1100)
committerAlex Brainman <alex.brainman@gmail.com>
Thu, 12 Oct 2017 07:12:36 +0000 (07:12 +0000)
Current code assumes that SetFileCompletionNotificationModes
is safe to call even if we know that it is not safe to use
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS flag. It appears (see issue #22149),
SetFileCompletionNotificationModes crashes when we call it without
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS flag.

Do not call SetFileCompletionNotificationModes in that situation.
We are allowed to do that, because SetFileCompletionNotificationModes
is just an optimisation.

Fixes #22149

Change-Id: I0ad3aff4eabd8c27739417a62c286b1819ae166a
Reviewed-on: https://go-review.googlesource.com/69870
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/internal/poll/fd_windows.go

index 5118e3f7690d2febe013ce7b6650cf67337dd9d7..dffbdc0957e86eee5e2a9cf4a6f09ab3cc0a1e20 100644 (file)
@@ -31,11 +31,40 @@ var (
 // package uses CancelIoEx API, if present, otherwise it fallback
 // to CancelIo.
 
-var (
-       canCancelIO                               bool // determines if CancelIoEx API is present
-       skipSyncNotif                             bool
-       hasLoadSetFileCompletionNotificationModes bool
-)
+var canCancelIO bool // determines if CancelIoEx API is present
+
+// This package uses SetFileCompletionNotificationModes Windows API
+// to skip calling GetQueuedCompletionStatus if an IO operation completes
+// synchronously. Unfortuently SetFileCompletionNotificationModes is not
+// available on Windows XP. Also there is a known bug where
+// SetFileCompletionNotificationModes crashes on some systems
+// (see http://support.microsoft.com/kb/2568167 for details).
+
+var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use
+
+// checkSetFileCompletionNotificationModes verifies that
+// SetFileCompletionNotificationModes Windows API is present
+// on the system and is safe to use.
+// See http://support.microsoft.com/kb/2568167 for details.
+func checkSetFileCompletionNotificationModes() {
+       err := syscall.LoadSetFileCompletionNotificationModes()
+       if err != nil {
+               return
+       }
+       protos := [2]int32{syscall.IPPROTO_TCP, 0}
+       var buf [32]syscall.WSAProtocolInfo
+       len := uint32(unsafe.Sizeof(buf))
+       n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
+       if err != nil {
+               return
+       }
+       for i := int32(0); i < n; i++ {
+               if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
+                       return
+               }
+       }
+       useSetFileCompletionNotificationModes = true
+}
 
 func init() {
        var d syscall.WSAData
@@ -44,26 +73,7 @@ func init() {
                initErr = e
        }
        canCancelIO = syscall.LoadCancelIoEx() == nil
-       hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
-       if hasLoadSetFileCompletionNotificationModes {
-               // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
-               // http://support.microsoft.com/kb/2568167
-               skipSyncNotif = true
-               protos := [2]int32{syscall.IPPROTO_TCP, 0}
-               var buf [32]syscall.WSAProtocolInfo
-               len := uint32(unsafe.Sizeof(buf))
-               n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
-               if err != nil {
-                       skipSyncNotif = false
-               } else {
-                       for i := int32(0); i < n; i++ {
-                               if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
-                                       skipSyncNotif = false
-                                       break
-                               }
-                       }
-               }
-       }
+       checkSetFileCompletionNotificationModes()
 }
 
 // operation contains superset of data necessary to perform all async IO.
@@ -347,12 +357,12 @@ func (fd *FD) Init(net string, pollable bool) (string, error) {
        if err != nil {
                return "", err
        }
-       if hasLoadSetFileCompletionNotificationModes {
+       if useSetFileCompletionNotificationModes {
                // We do not use events, so we can skip them always.
                flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
                // It's not safe to skip completion notifications for UDP:
                // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
-               if skipSyncNotif && (net == "tcp" || net == "file") {
+               if net == "tcp" || net == "file" {
                        flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
                }
                err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags)