From e3cfec08e350c59e766b3ac828c802668b7aca73 Mon Sep 17 00:00:00 2001 From: Igor Bazhitov Date: Mon, 3 Jan 2022 21:27:16 +0300 Subject: [PATCH] Fix a data race between Conn creation and its automatic closing `go test -race .` detects a data race when a Conn instance is automatically closed when the provided context's deadline is missed. Fix the data race by launching the corresponding goroutine only after all Conn's fields had been initialized. --- conn.go | 9 +++++---- conn_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/conn.go b/conn.go index 76fc5cd..c50bfe3 100644 --- a/conn.go +++ b/conn.go @@ -284,10 +284,6 @@ func newConn(tr transport, opts ...ConnOption) (*Conn, error) { conn.ctx = context.Background() } conn.ctx, conn.cancelCtx = context.WithCancel(conn.ctx) - go func() { - <-conn.ctx.Done() - conn.Close() - }() conn.calls = newCallTracker() if conn.handler == nil { @@ -302,6 +298,11 @@ func newConn(tr transport, opts ...ConnOption) (*Conn, error) { conn.outHandler = &outputHandler{conn: conn} conn.names = newNameTracker() conn.busObj = conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus") + + go func() { + <-conn.ctx.Done() + conn.Close() + }() return conn, nil } diff --git a/conn_test.go b/conn_test.go index b73fddd..e1cb8df 100644 --- a/conn_test.go +++ b/conn_test.go @@ -798,3 +798,25 @@ func TestCancellingContextClosesConnection(t *testing.T) { t.Errorf("expected connection to be closed, but got: %v", err) } } + +// TestTimeoutContextClosesConnection checks that a Conn instance is closed after +// the passed context's deadline is missed. +// The test also checks that there's no data race between Conn creation and its +// automatic closing. +func TestTimeoutContextClosesConnection(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 0) + defer cancel() + + bus, err := NewConn(rwc{}, WithContext(ctx)) + if err != nil { + t.Fatal(err) + } + + // wait until the connection is actually closed + time.Sleep(50 * time.Millisecond) + + err = bus.BusObject().Call("org.freedesktop.DBus.Peer.Ping", 0).Store() + if err != ErrClosed { + t.Errorf("expected connection to be closed, but got: %v", err) + } +}