From 2b01132c9f903247207cd0ac29cdaf55fdf96885 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Sun, 8 Mar 2026 14:18:04 +0100 Subject: [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 LUCI-TryBot-Result: Go LUCI Reviewed-by: Alex Brainman Reviewed-by: Mark Freeman (cherry picked from commit d3651c588846e1147e5a72f71c133dc8288e1e13) Reviewed-on: https://go-review.googlesource.com/c/go/+/754082 Reviewed-by: Cherry Mui --- src/internal/poll/sendfile_windows.go | 4 +++- src/net/sendfile.go | 2 ++ src/net/sendfile_stub.go | 2 ++ src/net/sendfile_test.go | 11 +++++++++++ src/net/sendfile_windows.go | 3 +++ 5 files changed, 21 insertions(+), 1 deletion(-) 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() } -- cgit v1.3