Repository: go
Issue: bufio: Reader.WriteTo makes an initial empty write
Labels: NeedsInvestigation,BugReport

### Go version

go version go1.24rc2 linux/amd64

### Output of `go env` in your module/workspace:

```shell
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/root/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/root/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3215251769=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/root/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/root/go'
GOPRIVATE=''
GOPROXY='direct'
GOROOT='/usr/lib/golang'
GOSUMDB='off'
GOTELEMETRY='local'
GOTELEMETRYDIR='/root/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='local'
GOTOOLDIR='/usr/lib/golang/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24rc2'
GOWORK=''
PKG_CONFIG='pkg-config'
```

### What did you do?

passing an bufio.Reader to io.Copy() results in an empty write() being issued. An empty write is normally not really an issue however in my case the writer is a unixpacket (SOCK_SEQPACKET) socket connection. In that case the empty write causes and empty read on the server. An an empty read() returns 0 which means the server misinterprets that message as EOF and closes the socket.

Consider this small example program, the program reads from stidn and writes that to the server running in the goroutine via io.Copy()

```go
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

const socketName = "/tmp/testsock123"
const socketType = "unixpacket" // switch to "unix" and it works

func main() {
	buffered := flag.Bool("bufio", false, "use bufio")
	flag.Parse()

	os.Remove(socketName)
	socket, err := net.ListenUnix(socketType, &net.UnixAddr{Name: socketName, Net: socketType})
	if err != nil {
		log.Fatalln(err)
	}

	serverChan := make(chan struct{})
	// server routine
	go func() {
		conn, err := socket.Accept()
		if err != nil {
			log.Fatalln(err)
		}
		buf := make([]byte, 1024)
		for {
			i, err := conn.Read(buf)
			if err != nil {
				if err == io.EOF {
					fmt.Println("server got EOF")
					serverChan <- struct{}{}
					return
				}
				log.Fatalln(err)
			}
			fmt.Printf("read %d bytes, msg: %s\n", i, string(buf[:i]))
		}

	}()

	conn, err := net.DialUnix(socketType, nil, &net.UnixAddr{Name: socketName, Net: socketType})
	if err != nil {
		log.Fatalln(err)
	}

	var reader io.Reader = os.Stdin
	if *buffered {
		reader = bufio.NewReader(os.Stdin)
	}
	_, err = io.Copy(conn, reader)
	if err != nil {
		log.Fatalln(err)
	}
	conn.Close()
	<-serverChan
}

```



### What did you see happen?

Only if the reader is wrapped in an bufio.Reader there is an extra empty write being made to the server. The server considers this to be an EOF and closes before the actual writes are made.
Not using bufio makes it work.


The example program:
```
$ go run main.go <<<"test"
read 5 bytes, msg: test

server got EOF

# using bufio makes it no longer work
$ go run main.go -bufio <<<"test"
server got EOF
```

strace clearly shows the behavior
```
...
write(4, "", 0)                         = 0
server got EOF
read(0, "test\n", 32768)                = 5
write(4, "test\n", 5)                   = 5
...
```

I guess for most cases the empty write does not matter (i.e. files or other stream based sockets) so most would not notice this but in case of SOCK_SEQPACKET/unixpacket it is important. 

### What did you expect to see?

Using bufio.Reader should not result in empty writes during io.Copy(). As far as I can tell this is because io.Copy() used the WriterTo() implementation here:
https://cs.opensource.google/go/go/+/refs/tags/go1.23.5:src/bufio/bufio.go;l=518-521

So I think the bufio WriterTo() should be fixed to not cause empty write()'s. It should only have to write there if there is something in the buffer.