aboutsummaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorBasavaraj PB <basavarajbankolli76@gmail.com>2026-03-13 11:08:32 +0530
committerGopher Robot <gobot@golang.org>2026-03-23 13:47:18 -0700
commitf26befb380e7b0a5e8c083cacfcd141b4c2d413a (patch)
tree6e80e2697706ca135c117388add4fc972a791507 /src/net
parente1bc5cea825171f68f928686ed02a0d0abddd84c (diff)
downloadgo-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.go7
-rw-r--r--src/net/unixsock_test.go95
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)
+ }
+ })
+}