Skip to content

Commit

Permalink
net: don't return non-nil interface values as Source, Addr in OpError
Browse files Browse the repository at this point in the history
Fixes golang#10992.

Change-Id: Ia376e4de118993b43e5813da57ab25fea8122048
Reviewed-on: https://go-review.googlesource.com/10476
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
cixtor committed Jun 13, 2015
1 parent 38e3427 commit 22829bd
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 76 deletions.
96 changes: 91 additions & 5 deletions src/net/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,38 @@ func (e *OpError) isValid() error {
return fmt.Errorf("OpError.Net is empty: %v", e)
}
for _, addr := range []Addr{e.Source, e.Addr} {
if addr != nil {
switch addr.(type) {
case *TCPAddr, *UDPAddr, *IPAddr, *IPNet, *UnixAddr, *pipeAddr, fileAddr:
default:
return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
switch addr := addr.(type) {
case nil:
case *TCPAddr:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case *UDPAddr:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case *IPAddr:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case *IPNet:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case *UnixAddr:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case *pipeAddr:
if addr == nil {
return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
}
case fileAddr:
if addr == "" {
return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e)
}
default:
return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
}
}
if e.Err == nil {
Expand Down Expand Up @@ -133,6 +159,35 @@ func TestDialError(t *testing.T) {
}
}

func TestProtocolDialError(t *testing.T) {
switch runtime.GOOS {
case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
}

for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
var err error
switch network {
case "tcp":
_, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16})
case "udp":
_, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16})
case "ip:4294967296":
_, err = DialIP(network, nil, nil)
case "unix", "unixpacket", "unixgram":
_, err = DialUnix(network, nil, &UnixAddr{Name: "//"})
}
if err == nil {
t.Errorf("%s: should fail", network)
continue
}
if err = parseDialError(err); err != nil {
t.Errorf("%s: %v", network, err)
continue
}
}
}

var listenErrorTests = []struct {
network, address string
}{
Expand Down Expand Up @@ -222,6 +277,37 @@ func TestListenPacketError(t *testing.T) {
}
}

func TestProtocolListenError(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}

for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
var err error
switch network {
case "tcp":
_, err = ListenTCP(network, &TCPAddr{Port: 1 << 16})
case "udp":
_, err = ListenUDP(network, &UDPAddr{Port: 1 << 16})
case "ip:4294967296":
_, err = ListenIP(network, nil)
case "unix", "unixpacket":
_, err = ListenUnix(network, &UnixAddr{Name: "//"})
case "unixgram":
_, err = ListenUnixgram(network, &UnixAddr{Name: "//"})
}
if err == nil {
t.Errorf("%s: should fail", network)
continue
}
if err = parseDialError(err); err != nil {
t.Errorf("%s: %v", network, err)
continue
}
}
}

// parseReadError parses nestedErr and reports whether it is a valid
// error value from Read functions.
// It returns nil when nestedErr is valid.
Expand Down
7 changes: 7 additions & 0 deletions src/net/iprawsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func (a *IPAddr) isWildcard() bool {
return a.IP.IsUnspecified()
}

func (a *IPAddr) opAddr() Addr {
if a == nil {
return nil
}
return a
}

// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
Expand Down
8 changes: 4 additions & 4 deletions src/net/iprawsock_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
// SetWriteDeadline. On packet-oriented connections, write timeouts
// are rare.
func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
}

// WriteTo implements the PacketConn WriteTo method.
Expand All @@ -59,7 +59,7 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
// b and the associated out-of-band data from oob. It returns the
// number of payload and out-of-band bytes written.
func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
}

// DialIP connects to the remote address raddr on the network protocol
Expand All @@ -70,13 +70,13 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
}

func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: syscall.EPLAN9}
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
}

// ListenIP listens for incoming IP packets addressed to the local
// address laddr. The returned connection's ReadFrom and WriteTo
// methods can be used to receive and send IP packets with per-packet
// addressing.
func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: syscall.EPLAN9}
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
}
30 changes: 15 additions & 15 deletions src/net/iprawsock_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,18 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
return 0, syscall.EINVAL
}
if c.fd.isConnected {
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
}
if addr == nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
}
sa, err := addr.sockaddr(c.fd.family)
if err != nil {
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
}
n, err := c.fd.writeTo(b, sa)
if err != nil {
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
}
return n, err
}
Expand All @@ -183,19 +183,19 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
return 0, 0, syscall.EINVAL
}
if c.fd.isConnected {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: ErrWriteToConnected}
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
}
if addr == nil {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: errMissingAddress}
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
}
var sa syscall.Sockaddr
sa, err = addr.sockaddr(c.fd.family)
if err != nil {
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
}
n, oobn, err = c.fd.writeMsg(b, oob, sa)
if err != nil {
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: err}
err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
}
return
}
Expand All @@ -210,19 +210,19 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
net, proto, err := parseNetwork(netProto)
if err != nil {
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: err}
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
}
switch net {
case "ip", "ip4", "ip6":
default:
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: UnknownNetworkError(netProto)}
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)}
}
if raddr == nil {
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: errMissingAddress}
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
}
fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial")
if err != nil {
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr, Addr: raddr, Err: err}
return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
}
return newIPConn(fd), nil
}
Expand All @@ -234,16 +234,16 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
net, proto, err := parseNetwork(netProto)
if err != nil {
return nil, &OpError{Op: "dial", Net: netProto, Source: nil, Addr: laddr, Err: err}
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
}
switch net {
case "ip", "ip4", "ip6":
default:
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: UnknownNetworkError(netProto)}
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
}
fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen")
if err != nil {
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr, Err: err}
return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
}
return newIPConn(fd), nil
}
18 changes: 18 additions & 0 deletions src/net/ipsock_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,24 @@ func netErr(e error) {
if !ok {
return
}
nonNilInterface := func(a Addr) bool {
switch a := a.(type) {
case *TCPAddr:
return a == nil
case *UDPAddr:
return a == nil
case *IPAddr:
return a == nil
default:
return false
}
}
if nonNilInterface(oe.Source) {
oe.Source = nil
}
if nonNilInterface(oe.Addr) {
oe.Addr = nil
}
if pe, ok := oe.Err.(*os.PathError); ok {
if _, ok = pe.Err.(syscall.ErrorString); ok {
oe.Err = pe.Err
Expand Down
7 changes: 7 additions & 0 deletions src/net/tcpsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ func (a *TCPAddr) isWildcard() bool {
return a.IP.IsUnspecified()
}

func (a *TCPAddr) opAddr() Addr {
if a == nil {
return nil
}
return a
}

// ResolveTCPAddr parses addr as a TCP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "tcp", "tcp4" or
Expand Down
6 changes: 3 additions & 3 deletions src/net/tcpsock_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
}
if raddr == nil {
return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
}
fd, err := dialPlan9(net, laddr, raddr)
if err != nil {
Expand Down Expand Up @@ -218,7 +218,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
}
if laddr == nil {
laddr = &TCPAddr{}
Expand Down
8 changes: 4 additions & 4 deletions src/net/tcpsock_posix.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: UnknownNetworkError(net)}
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
}
if raddr == nil {
return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: errMissingAddress}
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
}
return dialTCP(net, laddr, raddr, noDeadline)
}
Expand Down Expand Up @@ -202,7 +202,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
}

if err != nil {
return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
}
return newTCPConn(fd), nil
}
Expand Down Expand Up @@ -316,7 +316,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
switch net {
case "tcp", "tcp4", "tcp6":
default:
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: UnknownNetworkError(net)}
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
}
if laddr == nil {
laddr = &TCPAddr{}
Expand Down
7 changes: 7 additions & 0 deletions src/net/udpsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ func (a *UDPAddr) isWildcard() bool {
return a.IP.IsUnspecified()
}

func (a *UDPAddr) opAddr() Addr {
if a == nil {
return nil
}
return a
}

// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
// port name on the network net, which must be "udp", "udp4" or
Expand Down
Loading

0 comments on commit 22829bd

Please sign in to comment.