From 0ee521016c40bc46fe2d7c89bd8fb11cb8daca6e Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 4 Sep 2016 16:52:01 +0200 Subject: [PATCH] Don't use syscall.Close() on inherited fd Inherited file descriptor is encapsulated into a `File` using `os.NewFile()`. There is no `dup()` done by Go in this case and a finalizer will close the `File` (and the file descriptor if the file wasn't already closed) when it becomes out of reach. Using `syscall.Close()` will close the file descriptor but not the `File`. At some point, the finalizer will kick in, notice the file hasn't been closed and close again the file descriptor. If the file descriptor was reassigned to something else, we close an unrelated file descriptor. Tested with Go 1.7. Source code shows there is no `dup()` done when using `NewFile()`: - Go 1.7: https://github.com/golang/go/blob/release-branch.go1.7/src/os/file_unix.go#L50 - Go 1.6: https://github.com/golang/go/blob/release-branch.go1.6/src/os/file_unix.go#L50 - Go 1.5: https://github.com/golang/go/blob/release-branch.go1.5/src/os/file_unix.go#L48 - Go 1.4: https://github.com/golang/go/blob/release-branch.go1.4/src/os/file_unix.go#L40 --- goagain.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/goagain.go b/goagain.go index a69a2fd..82fe5f4 100644 --- a/goagain.go +++ b/goagain.go @@ -164,13 +164,14 @@ func Kill() error { } // Reconstruct a net.Listener from a file descriptior and name specified in the -// environment. Deal with Go's insistence on dup(2)ing file descriptors. +// environment. func Listener() (l net.Listener, err error) { var fd uintptr if _, err = fmt.Sscan(os.Getenv("GOAGAIN_FD"), &fd); nil != err { return } - l, err = net.FileListener(os.NewFile(fd, os.Getenv("GOAGAIN_NAME"))) + f := os.NewFile(fd, os.Getenv("GOAGAIN_NAME")) + l, err = net.FileListener(f) if nil != err { return } @@ -183,7 +184,7 @@ func Listener() (l net.Listener, err error) { ) return } - if err = syscall.Close(int(fd)); nil != err { + if err = f.Close(); nil != err { return } return