unix: fix event port panic after close

Fixes golang/go#54363

Change-Id: I38813aefaf58ef91605e0a6e3e6622c8a39d6a8d
Reviewed-on: https://go-review.googlesource.com/c/sys/+/422338
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Auto-Submit: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Nahum Shalman
2022-09-08 16:41:24 +00:00
committed by Gopher Robot
parent 7ac13a9a92
commit 27713097b9
3 changed files with 129 additions and 50 deletions
+57
View File
@@ -177,3 +177,60 @@ func TestEventPortDissociateAlreadyGone(t *testing.T) {
// The maps should be empty and there should be no pending events
port.checkInternals(t, 0, 0, 0, 0)
}
// Regression test for spuriously triggering a panic about memory mismanagement
// that can be triggered by an event processing thread trying to process an event
// after a different thread has already called port.Close().
// Implemented as an internal test so that we can just simulate the Close()
// because if you call close first in the same thread, things work properly
// anyway.
func TestEventPortGetAfterClose(t *testing.T) {
port, err := NewEventPort()
if err != nil {
t.Fatalf("NewEventPort failed: %v", err)
}
// Create, associate, and delete 2 files
for i := 0; i < 2; i++ {
tmpfile, err := os.CreateTemp("", "eventport")
if err != nil {
t.Fatalf("unable to create tempfile: %v", err)
}
path := tmpfile.Name()
stat, err := os.Stat(path)
if err != nil {
t.Fatalf("unable to stat tempfile: %v", err)
}
err = port.AssociatePath(path, stat, FILE_MODIFIED, nil)
if err != nil {
t.Fatalf("unable to AssociatePath tempfile: %v", err)
}
err = os.Remove(path)
if err != nil {
t.Fatalf("unable to Remove tempfile: %v", err)
}
}
n, err := port.Pending()
if err != nil {
t.Errorf("Pending failed: %v", err)
}
if n != 2 {
t.Errorf("expected 2 pending events, got %d", n)
}
// Simulate a close from a different thread
port.fds = nil
port.paths = nil
port.cookies = nil
// Ensure that we get back reasonable errors rather than panic
_, err = port.GetOne(nil)
if err == nil || err.Error() != "this EventPort is already closed" {
t.Errorf("didn't receive expected error of 'this EventPort is already closed'; got: %v", err)
}
events := make([]PortEvent, 2)
n, err = port.Get(events, 1, nil)
if n != 0 {
t.Errorf("expected to get back 0 events, got %d", n)
}
if err == nil || err.Error() != "this EventPort is already closed" {
t.Errorf("didn't receive expected error of 'this EventPort is already closed'; got: %v", err)
}
}