From 38c5469e7522db0c9435a5c33e0e0629113c4952 Mon Sep 17 00:00:00 2001 From: Erik Sipsma Date: Wed, 18 Dec 2019 18:46:59 +0000 Subject: [PATCH] Only close epoller FD at most once. Previously, multiple calls to epoller.Close() could result in unix.Close being called on the same FD value multiple times. This made it easy for consumers to create race conditions where calls to Close after the first one were closing unrelated FDs in the process that happened to use the same value of the epoller FD. This change uses sync.Once to ensure that unix.Close is only called once, with subsequent calls to Close returning "file already closed" instead. Signed-off-by: Erik Sipsma --- console_linux.go | 7 ++++++- console_linux_test.go | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/console_linux.go b/console_linux.go index 42274e1..c1c839e 100644 --- a/console_linux.go +++ b/console_linux.go @@ -58,6 +58,7 @@ type Epoller struct { efd int mu sync.Mutex fdMapping map[int]*EpollConsole + closeOnce sync.Once } // NewEpoller returns an instance of epoller with a valid epoll fd. @@ -151,7 +152,11 @@ func (e *Epoller) getConsole(sysfd int) *EpollConsole { // Close closes the epoll fd func (e *Epoller) Close() error { - return unix.Close(e.efd) + closeErr := os.ErrClosed // default to "file already closed" + e.closeOnce.Do(func() { + closeErr = unix.Close(e.efd) + }) + return closeErr } // EpollConsole acts like a console but registers its file descriptor with an diff --git a/console_linux_test.go b/console_linux_test.go index aba8015..a42db4c 100644 --- a/console_linux_test.go +++ b/console_linux_test.go @@ -85,4 +85,12 @@ func TestEpollConsole(t *testing.T) { if out := b.String(); out != expectedOutput { t.Errorf("unexpected output %q", out) } + + // make sure multiple Close calls return os.ErrClosed after the first + if err := epoller.Close(); err != nil { + t.Fatal(err) + } + if err := epoller.Close(); err != os.ErrClosed { + t.Fatalf("unexpected error returned from second call to epoller.Close(): %v", err) + } }