diff options
| author | Basavaraj PB <basavarajbankolli76@gmail.com> | 2026-03-13 11:08:32 +0530 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-23 13:47:18 -0700 |
| commit | f26befb380e7b0a5e8c083cacfcd141b4c2d413a (patch) | |
| tree | 6e80e2697706ca135c117388add4fc972a791507 /src/net | |
| parent | e1bc5cea825171f68f928686ed02a0d0abddd84c (diff) | |
| download | go-f26befb380e7b0a5e8c083cacfcd141b4c2d413a.tar.xz | |
net: avoid wrapping io.EOF in UnixConn read methods
The io.Reader contract requires that Read methods return io.EOF
directly instead of wrapping it in another error.
Currently UnixConn.ReadFromUnix, ReadFrom, and ReadMsgUnix wrap
io.EOF inside net.OpError, causing callers checking for io.EOF
to fail.
Fix by avoiding wrapping when err == io.EOF.
Fixes #78137
Change-Id: Ibb4e67cfb4c727c668ad79d1fb9e205f9b7e1903
Reviewed-on: https://go-review.googlesource.com/c/go/+/754960
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Nicholas Husin <nsh@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Basavaraj P <basavarajbankolli76@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Auto-Submit: Nicholas Husin <nsh@golang.org>
Diffstat (limited to 'src/net')
| -rw-r--r-- | src/net/unixsock.go | 7 | ||||
| -rw-r--r-- | src/net/unixsock_test.go | 95 |
2 files changed, 99 insertions, 3 deletions
diff --git a/src/net/unixsock.go b/src/net/unixsock.go index 0ee79f35de..47ab31fd7f 100644 --- a/src/net/unixsock.go +++ b/src/net/unixsock.go @@ -6,6 +6,7 @@ package net import ( "context" + "io" "os" "sync" "syscall" @@ -108,7 +109,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { return 0, nil, syscall.EINVAL } n, addr, err := c.readFrom(b) - if err != nil { + if err != nil && err != io.EOF { err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } return n, addr, err @@ -120,7 +121,7 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { return 0, nil, syscall.EINVAL } n, addr, err := c.readFrom(b) - if err != nil { + if err != nil && err != io.EOF { err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } if addr == nil { @@ -141,7 +142,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd return 0, 0, 0, nil, syscall.EINVAL } n, oobn, flags, addr, err = c.readMsg(b, oob) - if err != nil { + if err != nil && err != io.EOF { err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } return diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go index 3e4a14b255..9c2d309153 100644 --- a/src/net/unixsock_test.go +++ b/src/net/unixsock_test.go @@ -9,7 +9,9 @@ package net import ( "bytes" "internal/testenv" + "io" "os" + "path/filepath" "reflect" "runtime" "syscall" @@ -476,3 +478,96 @@ func TestUnixUnlink(t *testing.T) { l.Close() }) } + +// Ensure UnixConn read methods return io.EOF directly instead of wrapping it +// in net.OpError, per the io.Reader contract. See issue #78137. +func TestUnixConnReadEOF(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("unix sockets not reliable on windows") + } + if !testableNetwork("unix") { + t.Skip("unix test") + } + dir := t.TempDir() + addr := &UnixAddr{ + Name: filepath.Join(dir, "sock"), + Net: "unix", + } + + listen := func(t *testing.T) *UnixListener { + ln, err := ListenUnix("unix", addr) + if err != nil { + t.Fatal(err) + } + return ln + } + + startServer := func(t *testing.T, ln *UnixListener) { + go func() { + srv, err := ln.AcceptUnix() + if err != nil { + t.Error(err) + return + } + srv.Close() + }() + } + + dial := func(t *testing.T) *UnixConn { + cl, err := DialUnix("unix", nil, addr) + if err != nil { + t.Fatal(err) + } + return cl + } + + // Test ReadMsgUnix + t.Run("ReadMsgUnix", func(t *testing.T) { + ln := listen(t) + defer ln.Close() + + startServer(t, ln) + + cl := dial(t) + defer cl.Close() + + _, _, _, _, err := cl.ReadMsgUnix(make([]byte, 1), nil) + if err != io.EOF { + t.Fatalf("ReadMsgUnix returned %v, want io.EOF", err) + } + }) + + // Test ReadFromUnix + t.Run("ReadFromUnix", func(t *testing.T) { + ln := listen(t) + defer ln.Close() + + startServer(t, ln) + + cl := dial(t) + defer cl.Close() + + buf := make([]byte, 1) + _, _, err := cl.ReadFromUnix(buf) + if err != io.EOF { + t.Fatalf("ReadFromUnix returned %v, want io.EOF", err) + } + }) + + // Test ReadFrom + t.Run("ReadFrom", func(t *testing.T) { + ln := listen(t) + defer ln.Close() + + startServer(t, ln) + + cl := dial(t) + defer cl.Close() + + buf := make([]byte, 1) + _, _, err := cl.ReadFrom(buf) + if err != io.EOF { + t.Fatalf("ReadFrom returned %v, want io.EOF", err) + } + }) +} |
