diff options
| author | qmuntal <quimmuntal@gmail.com> | 2026-03-08 14:18:04 +0100 |
|---|---|---|
| committer | Carlos Amedee <carlos@golang.org> | 2026-03-20 09:33:51 -0700 |
| commit | 2b01132c9f903247207cd0ac29cdaf55fdf96885 (patch) | |
| tree | 6efb549992d39c927970a613ea1bf42c882a6000 | |
| parent | ba8c3d07a7d0a161f6cfcddc31077df1d8f096c0 (diff) | |
| download | go-2b01132c9f903247207cd0ac29cdaf55fdf96885.tar.xz | |
[release-branch.go1.26] runtime/poll: fix race condition in Window's SendFile
The destination of SendFile is a socket, which doesn't support file
offsets. There is no need to keep track of the file offset, and doing
so causes a race between SendFile and Read.
While here, make sure that SendFile tests do call poll.SendFile.
Updates #78015
Fixes #78019
Change-Id: I8cce45c0c110e848d9bdbc5ba340b92ca041f0a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/752860
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
(cherry picked from commit d3651c588846e1147e5a72f71c133dc8288e1e13)
Reviewed-on: https://go-review.googlesource.com/c/go/+/754082
Reviewed-by: Cherry Mui <cherryyz@google.com>
| -rw-r--r-- | src/internal/poll/sendfile_windows.go | 4 | ||||
| -rw-r--r-- | src/net/sendfile.go | 2 | ||||
| -rw-r--r-- | src/net/sendfile_stub.go | 2 | ||||
| -rw-r--r-- | src/net/sendfile_test.go | 11 | ||||
| -rw-r--r-- | src/net/sendfile_windows.go | 3 |
5 files changed, 21 insertions, 1 deletions
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go index 2bdfecf013..e0bb1ae182 100644 --- a/src/internal/poll/sendfile_windows.go +++ b/src/internal/poll/sendfile_windows.go @@ -68,8 +68,10 @@ func SendFile(fd *FD, src uintptr, size int64) (written int64, err error, handle chunkSize = size } - fd.setOffset(startpos + written) n, err := fd.execIO('w', func(o *operation) (uint32, error) { + off := startpos + written + o.o.OffsetHigh = uint32(off >> 32) + o.o.Offset = uint32(off) err := syscall.TransmitFile(fd.Sysfd, hsrc, uint32(chunkSize), 0, &o.o, nil, syscall.TF_WRITE_BEHIND) if err != nil { return 0, err diff --git a/src/net/sendfile.go b/src/net/sendfile.go index 0e0fcc40ff..572c368ae2 100644 --- a/src/net/sendfile.go +++ b/src/net/sendfile.go @@ -12,6 +12,8 @@ import ( "syscall" ) +var testHookSupportsSendfile func() bool + // sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go index 17d8d5448f..380c590e26 100644 --- a/src/net/sendfile_stub.go +++ b/src/net/sendfile_stub.go @@ -8,6 +8,8 @@ package net import "io" +var testHookSupportsSendfile func() bool + func supportsSendfile() bool { return false } diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index 437d181508..60e22bdede 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -28,6 +28,16 @@ const ( newtonSHA256 = "d4a9ac22462b35e7821a4f2706c211093da678620a8f9997989ee7cf8d507bbd" ) +func hookSupportsSendfile(t *testing.T) { + if runtime.GOOS == "windows" { + origHook := testHookSupportsSendfile + testHookSupportsSendfile = func() bool { return true } + t.Cleanup(func() { + testHookSupportsSendfile = origHook + }) + } +} + // expectSendfile runs f, and verifies that internal/poll.SendFile successfully handles // a write to wantConn during f's execution. // @@ -35,6 +45,7 @@ const ( // expect a call to SendFile. func expectSendfile(t *testing.T, wantConn Conn, f func()) { t.Helper() + hookSupportsSendfile(t) if !supportsSendfile() { f() return diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go index 44ddb421a1..58ac8122db 100644 --- a/src/net/sendfile_windows.go +++ b/src/net/sendfile_windows.go @@ -12,5 +12,8 @@ import "internal/syscall/windows" // https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile // https://golang.org/issue/73746 func supportsSendfile() bool { + if testHookSupportsSendfile != nil { + return testHookSupportsSendfile() + } return windows.SupportUnlimitedTransmitFile() } |
