diff options
| author | Ian Lance Taylor <iant@golang.org> | 2025-01-26 21:52:58 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-02-06 17:08:54 -0800 |
| commit | 290ec2d92bca6472fdabce51fc331b3bcaa7129d (patch) | |
| tree | 521de9734127e3ce5cae85a6931562054132a8eb /src | |
| parent | 7c6b047ea14dcc6aa948f901956511c4e8691abf (diff) | |
| download | go-290ec2d92bca6472fdabce51fc331b3bcaa7129d.tar.xz | |
bufio: don't do empty Write at start of WriteTo
The empty Write will cause the wrong thing to happen when using
io.Copy to copy to a package-based stream.
Fixes #71424
Change-Id: I046a27539447182692ac76a8bdd422327345dd8d
Reviewed-on: https://go-review.googlesource.com/c/go/+/644535
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Reviewed-by: Damien Neil <dneil@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/bufio/bufio.go | 8 | ||||
| -rw-r--r-- | src/bufio/bufio_test.go | 2 | ||||
| -rw-r--r-- | src/bufio/net_test.go | 96 |
3 files changed, 102 insertions, 4 deletions
diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go index d589701e19..5244ce2e0c 100644 --- a/src/bufio/bufio.go +++ b/src/bufio/bufio.go @@ -519,9 +519,11 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) { b.lastByte = -1 b.lastRuneSize = -1 - n, err = b.writeBuf(w) - if err != nil { - return + if b.r < b.w { + n, err = b.writeBuf(w) + if err != nil { + return + } } if r, ok := b.rd.(io.WriterTo); ok { diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go index 63dd2ea432..742e195425 100644 --- a/src/bufio/bufio_test.go +++ b/src/bufio/bufio_test.go @@ -1149,7 +1149,7 @@ func (w errorWriterToTest) Write(p []byte) (int, error) { var errorWriterToTests = []errorWriterToTest{ {1, 0, nil, io.ErrClosedPipe, io.ErrClosedPipe}, {0, 1, io.ErrClosedPipe, nil, io.ErrClosedPipe}, - {0, 0, io.ErrUnexpectedEOF, io.ErrClosedPipe, io.ErrClosedPipe}, + {0, 0, io.ErrUnexpectedEOF, io.ErrClosedPipe, io.ErrUnexpectedEOF}, {0, 1, io.EOF, nil, nil}, } diff --git a/src/bufio/net_test.go b/src/bufio/net_test.go new file mode 100644 index 0000000000..9c609fbcca --- /dev/null +++ b/src/bufio/net_test.go @@ -0,0 +1,96 @@ +// Copyright 2025 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package bufio_test + +import ( + "bufio" + "io" + "net" + "path/filepath" + "strings" + "sync" + "testing" +) + +// TestCopyUnixpacket tests that we can use bufio when copying +// across a unixpacket socket. This used to fail due to an unnecessary +// empty Write call that was interpreted as an EOF. +func TestCopyUnixpacket(t *testing.T) { + tmpDir := t.TempDir() + socket := filepath.Join(tmpDir, "unixsock") + + // Start a unixpacket server. + addr := &net.UnixAddr{ + Name: socket, + Net: "unixpacket", + } + server, err := net.ListenUnix("unixpacket", addr) + if err != nil { + t.Fatal(err) + } + + // Start a goroutine for the server to accept one connection + // and read all the data sent on the connection, + // reporting the number of bytes read on ch. + ch := make(chan int, 1) + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + + tot := 0 + defer func() { + ch <- tot + }() + + serverConn, err := server.Accept() + if err != nil { + t.Error(err) + return + } + + buf := make([]byte, 1024) + for { + n, err := serverConn.Read(buf) + tot += n + if err == io.EOF { + return + } + if err != nil { + t.Error(err) + return + } + } + }() + + clientConn, err := net.DialUnix("unixpacket", nil, addr) + if err != nil { + // Leaves the server goroutine hanging. Oh well. + t.Fatal(err) + } + + defer wg.Wait() + defer clientConn.Close() + + const data = "data" + r := bufio.NewReader(strings.NewReader(data)) + n, err := io.Copy(clientConn, r) + if err != nil { + t.Fatal(err) + } + + if n != int64(len(data)) { + t.Errorf("io.Copy returned %d, want %d", n, len(data)) + } + + clientConn.Close() + tot := <-ch + + if tot != len(data) { + t.Errorf("server read %d, want %d", tot, len(data)) + } +} |
