From 71d9d4e12b2a83e8c98be6f53082d2e9d5acd962 Mon Sep 17 00:00:00 2001 From: siyul-park Date: Fri, 27 Sep 2024 20:00:07 -0400 Subject: [PATCH] fix: escape deathlock in agent --- pkg/agent/agent.go | 25 +++++++++++++++++-------- pkg/debug/debugger.go | 13 +++++-------- pkg/process/process.go | 6 +++--- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 5275686b..49037c5d 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -22,7 +22,6 @@ type Agent struct { mu sync.RWMutex } -// Ensure Agent implements LoadHook and UnloadHook interfaces. var _ symbol.LoadHook = (*Agent)(nil) var _ symbol.UnloadHook = (*Agent)(nil) @@ -117,7 +116,7 @@ func (a *Agent) Frames(id uuid.UUID) ([]*Frame, bool) { if !exists { return nil, false } - return append([]*Frame(nil), frames...), true + return frames[:], true } // Load adds a symbol and its hooks to the agent. @@ -202,9 +201,10 @@ func (a *Agent) Close() { // accept registers a process and notifies watchers. func (a *Agent) accept(proc *process.Process) { a.mu.Lock() - defer a.mu.Unlock() - if _, exists := a.processes[proc.ID()]; !exists { + _, exists := a.processes[proc.ID()] + + if !exists { a.processes[proc.ID()] = proc proc.AddExitHook(process.ExitFunc(func(err error) { @@ -215,14 +215,21 @@ func (a *Agent) accept(proc *process.Process) { delete(a.frames, proc.ID()) })) - for _, watcher := range a.watchers { - watcher.OnProcess(proc) - } - if _, exists := a.frames[proc.ID()]; !exists { a.frames[proc.ID()] = nil } } + + watchers := a.watchers[:] + + a.mu.Unlock() + + if !exists { + for i := len(watchers) - 1; i >= 0; i-- { + watcher := watchers[i] + watcher.OnProcess(proc) + } + } } func (a *Agent) hooks(proc *process.Process, sym *symbol.Symbol, in *port.InPort, out *port.OutPort) (packet.Hook, packet.Hook) { @@ -251,6 +258,7 @@ func (a *Agent) hooks(proc *process.Process, sym *symbol.Symbol, in *port.InPort } watchers := a.watchers[:] + a.mu.Unlock() for i := len(watchers) - 1; i >= 0; i-- { @@ -284,6 +292,7 @@ func (a *Agent) hooks(proc *process.Process, sym *symbol.Symbol, in *port.InPort } watchers := a.watchers[:] + a.mu.Unlock() for i := len(watchers) - 1; i >= 0; i-- { diff --git a/pkg/debug/debugger.go b/pkg/debug/debugger.go index ef36fde8..8f13d307 100644 --- a/pkg/debug/debugger.go +++ b/pkg/debug/debugger.go @@ -68,16 +68,13 @@ func (d *Debugger) Breakpoints() []*Breakpoint { d.mu.RLock() defer d.mu.RUnlock() - if len(d.breakpoints) == 0 { - return nil - } - return append([]*Breakpoint(nil), d.breakpoints...) + return d.breakpoints[:] } // Pause blocks until a breakpoint is hit or monitoring is done. func (d *Debugger) Pause(ctx context.Context) bool { - d.mu.RLock() - defer d.mu.RUnlock() + d.mu.Lock() + defer d.mu.Unlock() if d.current != nil { return true @@ -95,8 +92,8 @@ func (d *Debugger) Pause(ctx context.Context) bool { // Step continues execution until the next breakpoint is hit. func (d *Debugger) Step(ctx context.Context) bool { - d.mu.RLock() - defer d.mu.RUnlock() + d.mu.Lock() + defer d.mu.Unlock() if d.current != nil { go d.next(d.current) diff --git a/pkg/process/process.go b/pkg/process/process.go index decc9f64..cb793852 100644 --- a/pkg/process/process.go +++ b/pkg/process/process.go @@ -50,7 +50,7 @@ func (p *Process) ID() uuid.UUID { func (p *Process) Load(key string) any { p.mu.RLock() defer p.mu.RUnlock() - + return p.data[key] } @@ -58,7 +58,7 @@ func (p *Process) Load(key string) any { func (p *Process) Store(key string, val any) { p.mu.Lock() defer p.mu.Unlock() - + p.data[key] = val } @@ -66,7 +66,7 @@ func (p *Process) Store(key string, val any) { func (p *Process) Delete(key string) bool { p.mu.Lock() defer p.mu.Unlock() - + if _, ok := p.data[key]; ok { delete(p.data, key) return true