package poll_test
import (
+ "errors"
"fmt"
"internal/poll"
+ "internal/syscall/windows"
"os"
"sync"
"syscall"
"testing"
+ "unsafe"
)
type loggedFD struct {
})
}
}
+
+func TestWSASocketConflict(t *testing.T) {
+ s, err := windows.WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, windows.WSA_FLAG_OVERLAPPED)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fd := poll.FD{Sysfd: s, IsStream: true, ZeroReadIsEOF: true}
+ _, err = fd.Init("tcp", true)
+ if err != nil {
+ syscall.CloseHandle(s)
+ t.Fatal(err)
+ }
+ defer fd.Close()
+
+ const SIO_TCP_INFO = syscall.IOC_INOUT | syscall.IOC_VENDOR | 39
+ inbuf := uint32(0)
+ 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
+
+ // 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 {
+ t.Fatalf("could not create the event!")
+ }
+
+ // Set the low bit of the Event Handle so that the 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
+
+ if err = fd.WSAIoctl(
+ SIO_TCP_INFO,
+ (*byte)(unsafe.Pointer(&inbuf)),
+ uint32(unsafe.Sizeof(inbuf)),
+ (*byte)(unsafe.Pointer(&outbuf)),
+ uint32(unsafe.Sizeof(outbuf)),
+ &cbbr,
+ &ovs[0],
+ 0,
+ ); err != nil && !errors.Is(err, syscall.ERROR_IO_PENDING) {
+ t.Fatalf("could not perform the WSAIoctl: %v", err)
+ }
+
+ 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 {
+ 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 {
+ State uint32
+ Mss uint32
+ ConnectionTimeMs uint64
+ TimestampsEnabled bool
+ RttUs uint32
+ MinRttUs uint32
+ BytesInFlight uint32
+ Cwnd uint32
+ SndWnd uint32
+ RcvWnd uint32
+ RcvBuf uint32
+ BytesOut uint64
+ BytesIn uint64
+ BytesReordered uint32
+ BytesRetrans uint32
+ FastRetrans uint32
+ DupAcksIn uint32
+ TimeoutEpisodes uint32
+ SynRetrans uint8
+}
/* more fields might be present here. */
}
+type SecurityAttributes struct {
+ Length uint16
+ SecurityDescriptor uintptr
+ InheritHandle bool
+}
+
type FILE_BASIC_INFO struct {
CreationTime syscall.Filetime
LastAccessTime syscall.Filetime
//sys CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
+//sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW
//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036
procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation")
procSystemFunction036 = modadvapi32.NewProc("SystemFunction036")
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+ procCreateEventW = modkernel32.NewProc("CreateEventW")
procGetACP = modkernel32.NewProc("GetACP")
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
return
}
+func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0)
+ handle = syscall.Handle(r0)
+ if handle == 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func GetACP() (acp uint32) {
r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
acp = uint32(r0)
}
type overlappedEntry struct {
- key uintptr
+ key *pollDesc
op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
internal uintptr
qty uint32
}
func netpollopen(fd uintptr, pd *pollDesc) int32 {
- if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
+ if stdcall4(_CreateIoCompletionPort, fd, iocphandle, uintptr(unsafe.Pointer(pd)), 0) == 0 {
return int32(getlasterror())
}
return 0
mp.blocked = false
for i = 0; i < n; i++ {
op = entries[i].op
- if op != nil {
+ if op != nil && op.pd == entries[i].key {
errno = 0
qty = 0
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {