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>
This commit is contained in:
Basavaraj PB
2026-03-13 11:08:32 +05:30
committed by Gopher Robot
parent e1bc5cea82
commit f26befb380
3 changed files with 101 additions and 3 deletions

2
doc/next/78137.md Normal file
View File

@@ -0,0 +1,2 @@
net: UnixConn read methods now return io.EOF directly instead of
wrapping it in net.OpError when the underlying read returns EOF.

View File

@@ -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

View File

@@ -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)
}
})
}