Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/rpc: socket fd leak when server closes connection first #6897

Closed
gopherbot opened this issue Dec 5, 2013 · 5 comments
Closed

net/rpc: socket fd leak when server closes connection first #6897

gopherbot opened this issue Dec 5, 2013 · 5 comments
Milestone

Comments

@gopherbot
Copy link

by joshpoimboeuf:

After an RPC connection has been established, if the server closes the connection first,
the client.Close() call returns an error and doesn't close the socket file descriptor,
resulting in an FD leak.

To reproduce:

~ $ cat server.go
package main

import (
    "log"
    "net"
    "net/rpc"
    "os"
    "time"
)

type MyRpc int

func (_ *MyRpc) Foo(arg1, arg2 *int) error {
    return nil
}

func main() {
    log.Println("server starting")
    socketPath := "/tmp/test.sock"
    os.Remove(socketPath)
    go func() {
        myRpc := new(MyRpc)
        if err := rpc.Register(myRpc); err != nil {
            log.Fatal(err)
        }
        addr := &net.UnixAddr{Net: "unix", Name: socketPath}
        listener, err := net.ListenUnix("unix", addr)
        if err != nil {
            log.Fatal(err)
        }
        for {
            conn, err := listener.AcceptUnix()
            if err != nil {
                log.Fatal(err)
            }
            rpc.ServeConn(conn)
        }
    }()

    time.Sleep(2 * time.Second)
    log.Println("server exiting")
}
~ $ cat client.go
package main

import (
    "os/exec"
    "fmt"
    "log"
    "net/rpc"
    "os"
    "time"
)

func showFds() {
    procStr := fmt.Sprintf("/proc/%d/fd", os.Getpid())
    cmd := exec.Command("ls", "-l", procStr)
    output, err := cmd.CombinedOutput()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", output)
}

func main() {
    log.Println("client starting")
    client, err := rpc.Dial("unix", "/tmp/test.sock")
    if err != nil {
        log.Fatal(err)
    }
    log.Println("connection established")

    log.Println("FDs before server exit:")
    showFds()

    time.Sleep(5 * time.Second)

    log.Println("calling client.Close()")
    if err := client.Close(); err != nil {
        log.Println("client.Close() error: ", err)
    }

    log.Println("FDs after server exit:")
    showFds()

    log.Println("client exiting")
}
~ $ cat doit
go run server.go &
sleep 1
go run client.go
~ $ ./doit
2013/12/05 10:28:41 server starting
2013/12/05 10:28:42 client starting
2013/12/05 10:28:42 connection established
2013/12/05 10:28:42 FDs before server exit:
total 0
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 0 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 1 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 2 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 3 -> socket:[4560708]
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 4 -> anon_inode:[eventpoll]
lr-x------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 6 -> pipe:[4560709]
2013/12/05 10:28:43 server exiting
2013/12/05 10:28:47 calling client.Close()
2013/12/05 10:28:47 client.Close() error:  connection is shut down
2013/12/05 10:28:47 FDs after server exit:
total 0
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 0 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 1 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 2 -> /dev/pts/5
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 3 -> socket:[4560708]
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 4 -> anon_inode:[eventpoll]
lr-x------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 6 -> pipe:[4560712]
2013/12/05 10:28:47 client exiting

Notice the socket:[4560708] fd still exists after client.Close was called.

What steps will reproduce the problem?
See above programs and script.

What is the expected output?
The "socket:[4560708]" file descriptor should no longer be listed in the open
FDs for the client process.

What do you see instead?
lrwx------. 1 jpoimboe jpoimboe 64 Dec  5 10:28 3 -> socket:[4560708]

Which compiler are you using (5g, 6g, 8g, gccgo)?
6g

Which operating system are you using?
Linux

Which version are you using?  (run 'go version')
go version go1.2 linux/amd64

Please provide any additional information below.
@robpike
Copy link
Contributor

robpike commented Dec 19, 2013

Comment 1:

Should be fixed in the release. Leaks are bad.
See also 5792.

Labels changed: added release-go1.3maybe, repo-main.

Status changed to Accepted.

@rsc
Copy link
Contributor

rsc commented Apr 3, 2014

Comment 2:

Labels changed: added release-go1.3, removed release-go1.3maybe.

@gopherbot
Copy link
Author

Comment 3:

CL https://golang.org/cl/91830045 mentions this issue.

@gopherbot
Copy link
Author

Comment 4:

CL https://golang.org/cl/91230045 mentions this issue.

@bradfitz
Copy link
Contributor

Comment 5:

This issue was closed by revision 82ca308.

Status changed to Fixed.

@rsc rsc added this to the Go1.3 milestone Apr 14, 2015
@rsc rsc removed the release-go1.3 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants