Skip to content

Commit f259aed

Browse files
alexbrainmanrsc
authored andcommitted
[release-branch.go1.9] internal/poll: do not call SetFileCompletionNotificationModes if it is broken
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 <[email protected]> Reviewed-on: https://go-review.googlesource.com/70989 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alex Brainman <[email protected]>
1 parent 39d4bb9 commit f259aed

File tree

1 file changed

+37
-27
lines changed

1 file changed

+37
-27
lines changed

src/internal/poll/fd_windows.go

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,40 @@ var (
3131
// package uses CancelIoEx API, if present, otherwise it fallback
3232
// to CancelIo.
3333

34-
var (
35-
canCancelIO bool // determines if CancelIoEx API is present
36-
skipSyncNotif bool
37-
hasLoadSetFileCompletionNotificationModes bool
38-
)
34+
var canCancelIO bool // determines if CancelIoEx API is present
35+
36+
// This package uses SetFileCompletionNotificationModes Windows API
37+
// to skip calling GetQueuedCompletionStatus if an IO operation completes
38+
// synchronously. Unfortuently SetFileCompletionNotificationModes is not
39+
// available on Windows XP. Also there is a known bug where
40+
// SetFileCompletionNotificationModes crashes on some systems
41+
// (see http://support.microsoft.com/kb/2568167 for details).
42+
43+
var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use
44+
45+
// checkSetFileCompletionNotificationModes verifies that
46+
// SetFileCompletionNotificationModes Windows API is present
47+
// on the system and is safe to use.
48+
// See http://support.microsoft.com/kb/2568167 for details.
49+
func checkSetFileCompletionNotificationModes() {
50+
err := syscall.LoadSetFileCompletionNotificationModes()
51+
if err != nil {
52+
return
53+
}
54+
protos := [2]int32{syscall.IPPROTO_TCP, 0}
55+
var buf [32]syscall.WSAProtocolInfo
56+
len := uint32(unsafe.Sizeof(buf))
57+
n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
58+
if err != nil {
59+
return
60+
}
61+
for i := int32(0); i < n; i++ {
62+
if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
63+
return
64+
}
65+
}
66+
useSetFileCompletionNotificationModes = true
67+
}
3968

4069
func init() {
4170
var d syscall.WSAData
@@ -44,26 +73,7 @@ func init() {
4473
initErr = e
4574
}
4675
canCancelIO = syscall.LoadCancelIoEx() == nil
47-
hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
48-
if hasLoadSetFileCompletionNotificationModes {
49-
// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
50-
// http://support.microsoft.com/kb/2568167
51-
skipSyncNotif = true
52-
protos := [2]int32{syscall.IPPROTO_TCP, 0}
53-
var buf [32]syscall.WSAProtocolInfo
54-
len := uint32(unsafe.Sizeof(buf))
55-
n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len)
56-
if err != nil {
57-
skipSyncNotif = false
58-
} else {
59-
for i := int32(0); i < n; i++ {
60-
if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 {
61-
skipSyncNotif = false
62-
break
63-
}
64-
}
65-
}
66-
}
76+
checkSetFileCompletionNotificationModes()
6777
}
6878

6979
// operation contains superset of data necessary to perform all async IO.
@@ -344,12 +354,12 @@ func (fd *FD) Init(net string, pollable bool) (string, error) {
344354
if err != nil {
345355
return "", err
346356
}
347-
if hasLoadSetFileCompletionNotificationModes {
357+
if useSetFileCompletionNotificationModes {
348358
// We do not use events, so we can skip them always.
349359
flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE)
350360
// It's not safe to skip completion notifications for UDP:
351361
// http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx
352-
if skipSyncNotif && (net == "tcp" || net == "file") {
362+
if net == "tcp" || net == "file" {
353363
flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
354364
}
355365
err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags)

0 commit comments

Comments
 (0)