diff --git a/src/internal/poll/fd_windows_test.go b/src/internal/poll/fd_windows_test.go index 1cee18dcba..8bf92be7c3 100644 --- a/src/internal/poll/fd_windows_test.go +++ b/src/internal/poll/fd_windows_test.go @@ -133,23 +133,14 @@ func TestWSASocketConflict(t *testing.T) { var outbuf _TCP_INFO_v0 cbbr := uint32(0) - var ovs []syscall.Overlapped = make([]syscall.Overlapped, 2) - // Attempt to exercise behavior where a user-owned syscall.Overlapped - // induces an invalid pointer dereference in the Windows-specific version - // of runtime.netpoll. - ovs[1].Internal -= 1 - + var ov syscall.Overlapped // Create an event so that we can efficiently wait for completion // of a requested overlapped I/O operation. - ovs[0].HEvent, _ = windows.CreateEvent(nil, 0, 0, nil) - if ovs[0].HEvent == 0 { + ov.HEvent, _ = windows.CreateEvent(nil, 0, 0, nil) + if ov.HEvent == 0 { t.Fatalf("could not create the event!") } - - // Set the low bit of the Event Handle so that the completion - // of the overlapped I/O event will not trigger a completion event - // on any I/O completion port associated with the handle. - ovs[0].HEvent |= 0x1 + defer syscall.CloseHandle(ov.HEvent) if err = fd.WSAIoctl( SIO_TCP_INFO, @@ -158,7 +149,7 @@ func TestWSASocketConflict(t *testing.T) { (*byte)(unsafe.Pointer(&outbuf)), uint32(unsafe.Sizeof(outbuf)), &cbbr, - &ovs[0], + &ov, 0, ); err != nil && !errors.Is(err, syscall.ERROR_IO_PENDING) { t.Fatalf("could not perform the WSAIoctl: %v", err) @@ -167,14 +158,10 @@ func TestWSASocketConflict(t *testing.T) { if err != nil && errors.Is(err, syscall.ERROR_IO_PENDING) { // It is possible that the overlapped I/O operation completed // immediately so there is no need to wait for it to complete. - if res, err := syscall.WaitForSingleObject(ovs[0].HEvent, syscall.INFINITE); res != 0 { + if res, err := syscall.WaitForSingleObject(ov.HEvent, syscall.INFINITE); res != 0 { t.Fatalf("waiting for the completion of the overlapped IO failed: %v", err) } } - - if err = syscall.CloseHandle(ovs[0].HEvent); err != nil { - t.Fatalf("could not close the event handle: %v", err) - } } type _TCP_INFO_v0 struct { diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go index 59377bc588..8096c64e7e 100644 --- a/src/runtime/netpoll_windows.go +++ b/src/runtime/netpoll_windows.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/goarch" "runtime/internal/atomic" "unsafe" ) @@ -13,19 +14,82 @@ const _DWORD_MAX = 0xffffffff const _INVALID_HANDLE_VALUE = ^uintptr(0) -// net_op must be the same as beginning of internal/poll.operation. +// Sources are used to identify the event that created an overlapped entry. +// The source values are arbitrary. There is no risk of collision with user +// defined values because the only way to set the key of an overlapped entry +// is using the iocphandle, which is not accessible to user code. +const ( + netpollSourceReady = iota + 1 + netpollSourceBreak +) + +const ( + // sourceBits is the number of bits needed to represent a source. + // 4 bits can hold 16 different sources, which is more than enough. + // It is set to a low value so the overlapped entry key can + // contain as much bits as possible for the pollDesc pointer. + sourceBits = 4 // 4 bits can hold 16 different sources, which is more than enough. + sourceMasks = 1< (1<