-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Closed
Labels
Milestone
Description
What version of Go are you using (go version
)?
go version go1.7 linux/amd64
What operating system and processor architecture are you using (go env
)?
GOARCH="amd64"
GOOS="linux"
What did you do?
Ping 127.0.0.1 (localhost) with many goroutines. Try run few times:
package main
import (
"fmt"
"log"
"net"
"os"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
func doPing(host string) error {
network := "udp4"
address := "0.0.0.0"
protocol := 1 // Internet Control Message
mtype := ipv4.ICMPTypeEcho
c, err := icmp.ListenPacket(network, address)
if err != nil {
return err
}
defer c.Close()
dst := &net.UDPAddr{IP: net.ParseIP(host)}
wm := icmp.Message{
Type: mtype, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff, Seq: 1 << uint(0),
Data: []byte("ello gov'nor"),
},
}
wb, err := wm.Marshal(nil)
if err != nil {
return err
}
if n, err := c.WriteTo(wb, dst); err != nil {
return err
} else if n != len(wb) {
return fmt.Errorf("got %v; want %v", n, len(wb))
}
rb := make([]byte, 1500)
n, peer, err := c.ReadFrom(rb)
if err != nil {
return err
}
rm, err := icmp.ParseMessage(protocol, rb[:n])
if err != nil {
return err
}
switch rm.Type {
case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
return nil
default:
return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
}
}
func main() {
for i := 1; i < 1000; i++ {
go func() {
err := doPing("127.0.0.1")
if err != nil {
log.Fatal(err)
}
}()
}
}
What did you expect to see?
Nothing. No errors.
What did you see instead?
Maybe second close happens on another reused connection fd.
2016/09/02 18:51:08 file file+net datagram-oriented icmp: getsockopt: bad file descriptor
Minimal program to strace
package main
import "golang.org/x/net/icmp"
func main() {
c, _ := icmp.ListenPacket("udp4", "0.0.0.0")
c.Close()
}
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
close(3) = 0
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
bind(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
bind(4, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
close(4) = 0
close(3) = 0
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
fcntl(3, F_DUPFD_CLOEXEC, 0) = 4
fcntl(4, F_GETFL) = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0
getsockopt(4, SOL_SOCKET, SO_TYPE, [2], [4]) = 0
getsockname(4, {sa_family=AF_INET, sin_port=htons(20618), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
getpeername(4, 0xc42004dbc8, 0xc42004dbc4) = -1 ENOTCONN (Transport endpoint is not connected)
epoll_create1(EPOLL_CLOEXEC) = 5
epoll_ctl(5, EPOLL_CTL_ADD, 4, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=3043491584, u64=140255200542464}}) = 0
close(3) = 0
close(3) = -1 EBADF (Bad file descriptor)
epoll_ctl(5, EPOLL_CTL_DEL, 4, 0xc42004dda4) = 0
close(4) = 0
exit_group(0) = ?
+++ exited with 0 +++
Possible fix
When this defer syscall.Close(s)
removed from icmp/listen_posix.go:69
, no multiple closes on fd happens.