Skip to content

Commit feb1a48

Browse files
committed
api: fix panic in conn.NewWatcher()
Before this patch, `conn.c` was not checked for `nil` before calling its method. This could cause a panic if the connection was lost or closed. Closes #438
1 parent c0a8ad3 commit feb1a48

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

connection.go

+3
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,9 @@ func isFeatureInSlice(expected iproto.Feature, actualSlice []iproto.Feature) boo
14541454
//
14551455
// Since 1.10.0
14561456
func (conn *Connection) NewWatcher(key string, callback WatchCallback) (Watcher, error) {
1457+
if conn.c == nil {
1458+
return nil, ClientError{ErrConnectionNotReady, "client connection is not ready"}
1459+
}
14571460
// We need to check the feature because the IPROTO_WATCH request is
14581461
// asynchronous. We do not expect any response from a Tarantool instance
14591462
// That's why we can't just check the Tarantool response for an unsupported

tarantool_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -3550,6 +3550,51 @@ func TestConnection_NewWatcher(t *testing.T) {
35503550
}
35513551
}
35523552

3553+
func TestNewWatcherDuringReconnectOrAfterClose(t *testing.T) {
3554+
const server = "127.0.0.1:3015"
3555+
testDialer := dialer
3556+
testDialer.Address = server
3557+
3558+
inst, err := test_helpers.StartTarantool(test_helpers.StartOpts{
3559+
Dialer: testDialer,
3560+
InitScript: "config.lua",
3561+
Listen: server,
3562+
WaitStart: 100 * time.Millisecond,
3563+
ConnectRetry: 10,
3564+
RetryTimeout: 500 * time.Millisecond,
3565+
})
3566+
defer test_helpers.StopTarantoolWithCleanup(inst)
3567+
if err != nil {
3568+
t.Fatalf("Unable to start Tarantool: %s", err)
3569+
}
3570+
3571+
ctx, cancel := test_helpers.GetConnectContext()
3572+
defer cancel()
3573+
3574+
reconnectOpts := opts
3575+
reconnectOpts.Reconnect = 100 * time.Millisecond
3576+
reconnectOpts.MaxReconnects = 0
3577+
reconnectOpts.Notify = make(chan ConnEvent)
3578+
conn, err := Connect(ctx, testDialer, reconnectOpts)
3579+
if err != nil {
3580+
t.Fatalf("Connection was not established: %v", err)
3581+
}
3582+
defer conn.Close()
3583+
test_helpers.StopTarantool(inst)
3584+
3585+
for conn.ConnectedNow() {
3586+
time.Sleep(100 * time.Millisecond)
3587+
}
3588+
_, err = conn.NewWatcher("one", func(event WatchEvent) {})
3589+
assert.NotNil(t, err)
3590+
assert.ErrorContains(t, err, "client connection is not ready")
3591+
3592+
conn.Close()
3593+
_, err = conn.NewWatcher("two", func(event WatchEvent) {})
3594+
assert.NotNil(t, err)
3595+
assert.ErrorContains(t, err, "client connection is not ready")
3596+
}
3597+
35533598
func TestConnection_NewWatcher_noWatchersFeature(t *testing.T) {
35543599
test_helpers.SkipIfWatchersSupported(t)
35553600

0 commit comments

Comments
 (0)