mirror of
https://github.com/golang/go.git
synced 2026-04-02 09:20:29 +09:00
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:
committed by
Gopher Robot
parent
e1bc5cea82
commit
f26befb380
2
doc/next/78137.md
Normal file
2
doc/next/78137.md
Normal 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user