Skip to content

Commit 3be537e

Browse files
committed
net: use closesocket when closing socket os.File's on Windows
The WSASocket documentation states that the returned socket must be closed by calling closesocket instead of CloseHandle. The different File methods on the net package return an os.File that is not aware that it should use closesocket. Ideally, os.NewFile should detect that the passed handle is a socket and use the appropriate close function, but there is no reliable way to detect that a handle is a socket on Windows (see CL 671455). To work around this, we add a hidden function to the os package that can be used to return an os.File that uses closesocket. This approach is the same as used on Unix, which also uses a hidden function for other purposes. While here, fix a potential issue with FileConn, which was using File.Fd rather than File.SyscallConn to get the handle. This could result in the File being closed and garbage collected before the syscall was made. Fixes #73683. Change-Id: I179405f34c63cbbd555d8119e0f77157c670eb3e Reviewed-on: https://go-review.googlesource.com/c/go/+/672195 Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
1 parent a197a47 commit 3be537e

File tree

5 files changed

+229
-188
lines changed

5 files changed

+229
-188
lines changed

src/internal/poll/fd_windows.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ type FD struct {
318318
// message based socket connection.
319319
ZeroReadIsEOF bool
320320

321-
// Whether this is a file rather than a network socket.
321+
// Whether the handle is owned by os.File.
322322
isFile bool
323323

324324
// The kind of this file.
@@ -368,6 +368,7 @@ const (
368368
kindFile
369369
kindConsole
370370
kindPipe
371+
kindFileNet
371372
)
372373

373374
// Init initializes the FD. The Sysfd field should already be set.
@@ -388,6 +389,8 @@ func (fd *FD) Init(net string, pollable bool) error {
388389
fd.kind = kindConsole
389390
case "pipe":
390391
fd.kind = kindPipe
392+
case "file+net":
393+
fd.kind = kindFileNet
391394
default:
392395
// We don't actually care about the various network types.
393396
fd.kind = kindNet
@@ -453,7 +456,7 @@ func (fd *FD) destroy() error {
453456
fd.pd.close()
454457
var err error
455458
switch fd.kind {
456-
case kindNet:
459+
case kindNet, kindFileNet:
457460
// The net package uses the CloseFunc variable for testing.
458461
err = CloseFunc(fd.Sysfd)
459462
default:
@@ -494,7 +497,7 @@ func (fd *FD) Read(buf []byte) (int, error) {
494497
return 0, err
495498
}
496499
defer fd.readUnlock()
497-
if fd.isFile {
500+
if fd.kind == kindFile {
498501
fd.l.Lock()
499502
defer fd.l.Unlock()
500503
}
@@ -747,7 +750,7 @@ func (fd *FD) Write(buf []byte) (int, error) {
747750
return 0, err
748751
}
749752
defer fd.writeUnlock()
750-
if fd.isFile {
753+
if fd.kind == kindFile {
751754
fd.l.Lock()
752755
defer fd.l.Unlock()
753756
}

src/net/fd_windows.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ func (fd *netFD) accept() (*netFD, error) {
233233
return netfd, nil
234234
}
235235

236+
// Defined in os package.
237+
func newWindowsFile(h syscall.Handle, name string) *os.File
238+
236239
func (fd *netFD) dup() (*os.File, error) {
237240
// Disassociate the IOCP from the socket,
238241
// it is not safe to share a duplicated handle
@@ -251,5 +254,8 @@ func (fd *netFD) dup() (*os.File, error) {
251254
if err != nil {
252255
return nil, err
253256
}
254-
return os.NewFile(uintptr(h), fd.name()), nil
257+
// All WSASocket calls must be match with a syscall.Closesocket call,
258+
// but os.NewFile calls syscall.CloseHandle instead. We need to use
259+
// a hidden function so that the returned file is aware of this fact.
260+
return newWindowsFile(h, fd.name()), nil
255261
}

0 commit comments

Comments
 (0)