From 9d7ef9b255ba52b0b41514cf4a3b9f725aa5cebf Mon Sep 17 00:00:00 2001 From: Riccardo Manfrin <3090891+riccardomanfrin@users.noreply.github.com> Date: Thu, 28 May 2026 08:54:15 +0200 Subject: [PATCH] [client] Fix statemanager possible deadlock (#6228) 1. Stop() takes m.mu.Lock() and defers m.mu.Unlock() 2. <-m.done under lock 3. periodicStateSave defers close(m.done) 4. periodicStateSave calls PersistState() (line 256) which does m.mu.Lock() Double Stop() remains idempotent: second cancel() on dead ctx (no-op) and reads done already closed (immediate return). --- client/internal/statemanager/manager.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/internal/statemanager/manager.go b/client/internal/statemanager/manager.go index 2c9e46290..566905985 100644 --- a/client/internal/statemanager/manager.go +++ b/client/internal/statemanager/manager.go @@ -96,17 +96,19 @@ func (m *Manager) Stop(ctx context.Context) error { } m.mu.Lock() - defer m.mu.Unlock() + cancel := m.cancel + done := m.done + m.mu.Unlock() - if m.cancel == nil { + if cancel == nil { return nil } - m.cancel() + cancel() select { case <-ctx.Done(): return ctx.Err() - case <-m.done: + case <-done: } return nil