]> Cypherpunks repositories - gostls13.git/commitdiff
bufio: don't do empty Write at start of WriteTo
authorIan Lance Taylor <iant@golang.org>
Mon, 27 Jan 2025 05:52:58 +0000 (21:52 -0800)
committerGopher Robot <gobot@golang.org>
Fri, 7 Feb 2025 01:08:54 +0000 (17:08 -0800)
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>
src/bufio/bufio.go
src/bufio/bufio_test.go
src/bufio/net_test.go [new file with mode: 0644]

index d589701e19a85c19c860707843dfac8c645e4bb0..5244ce2e0ca9436b0fa8feead7c809a0f444da62 100644 (file)
@@ -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 {
index 63dd2ea4322cea1f3c4bd2a7aa12797c8a95902d..742e195425690332dcf32487df3834e04a4a38ea 100644 (file)
@@ -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 (file)
index 0000000..9c609fb
--- /dev/null
@@ -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))
+       }
+}