Skip to content

Fix UpdateActivatedProbes panic, refactor state checks, use stopping state - #290

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 6 commits into
mainfrom
theop-dd/fix-panic-update-probes
Sep 17, 2026
Merged

gh-worker-dd-mergequeue-cf854d[bot] merged 6 commits into
mainfrom
theop-dd/fix-panic-update-probes

Conversation

@theop-dd

@theop-dd theop-dd commented Sep 9, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

This PR fixes the UpdateActivatedProbes panic and hardens manager state handling during reader shutdown.

1. Fix panic in UpdateActivatedProbes

UpdateActivatedProbes called m.stop() (private, no lock) on validation failure instead of m.Stop() (public, acquires the lock). Since UpdateActivatedProbes releases stateLock before the end of the function, it could call stop without holding the lock, which is not expected. This is fixed by calling m.Stop(), which properly acquires its own lock after UpdateActivatedProbes releases it.

2. Refactor state checks from if to switch/case

Replace all inequality-based state checks (if m.state < initialized) with explicit switch/case statements. This makes the set of accepted states visible at each call site and eliminates reliance on the numeric ordering of the state enum.

Also rename the stopped constant to stopping to reflect its actual semantics: a transition state, not a terminal state.

3. Use the transient stopping state during reader shutdown

  • stopReaders() sets m.state = stopping before closing readers, then restores the previous state when it finishes (unless a concurrent Stop() has already moved the manager to reset).
  • stop() sets m.state = reset only after all resources have been released and rechecks the state after stopReaders() because that function temporarily releases the lock.
  • During stopping, only operations that touch PerfMap/RingBuffer readers are blocked:
    • Blocked: Start, Pause, Resume, NewPerfRing, NewRingBuffer — these interact with readers that are dead or shutting down.
    • Allowed: all getters (GetMap, GetProbe, GetProgram, etc.), probe operations (AddHook, DetachHook, CloneProgram, UpdateActivatedProbes), map/route operations (NewMap, UpdateMapRoutes, UpdateTailCallRoutes), CleanupNetworkNamespace, and Stop — these resources are not affected by stopReaders.

This prevents races where NewPerfRing/NewRingBuffer could create new readers during the stopReaders unlock window, while preserving the manager's state after a standalone StopReaders() call and still allowing probe and map operations during graceful shutdown.

4. Retract affected releases

Retract v0.8.5 and v0.8.6 in go.mod because these versions can panic.

Motivation

Follow-up to #288 and #289. The deadlock fix in #288 introduced an unlock window in stopReaders where m.state was set to reset too early, which broke concurrent accessors. The transient stopping state communicates that readers are shutting down while the other resources are still alive.

theop-dd and others added 3 commits September 9, 2026 09:06
Replace all 'if m.state < initialized' and similar inequality-based
state checks with explicit switch/case statements. This makes the
set of accepted states visible at each call site and avoids relying
on the numeric ordering of the state enum.

Also rename the 'stopped' state constant to 'stopping' to better
reflect its semantics (a transition, not a terminal state).

Co-authored-by: Cursor <cursoragent@cursor.com>
Treat 'stopping' the same as 'reset' in all manager methods except
Stop(), which must still accept 'stopping' so that the full cleanup
(detach probes, close maps) can proceed after StopReaders().

stopReaders() now sets m.state = stopping before closing readers.
stop() sets m.state = reset at the end, after all resources are freed,
instead of at the beginning.

Co-authored-by: Cursor <cursoragent@cursor.com>
@theop-dd
theop-dd force-pushed the theop-dd/fix-panic-update-probes branch from a1297c9 to 78cd5cc Compare September 10, 2026 12:08
@theop-dd theop-dd changed the title Theop dd/fix panic update probes Fix UpdateActivatedProbes panic, refactor state checks, use stopping state Sep 10, 2026
@theop-dd
theop-dd marked this pull request as ready for review September 10, 2026 12:18
@theop-dd
theop-dd requested a review from a team as a code owner September 10, 2026 12:18
Comment thread perfmap.go
m.stateLock.Lock()
defer m.stateLock.Unlock()
if m.state <= stopped {
if m.state <= stopping {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still relies upon enum ordering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This affect the perf map states and lock. I wanted to edit that on another PR and not on this one.

Comment thread perfmap.go
m.stateLock.Lock()
defer m.stateLock.Unlock()
if m.state <= stopped {
if m.state <= stopping {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still relies upon enum ordering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This affects the perf map states and lock. I wanted to edit that on another PR and not on this one.

Comment thread ringbuffer.go
rb.stateLock.Lock()
defer rb.stateLock.Unlock()
if rb.state <= stopped {
if rb.state <= stopping {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still relies upon enum ordering

@theop-dd theop-dd Sep 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This affect the ring buffer states and lock. I wanted to edit that on another PR and not on this one.

Comment thread ringbuffer.go
rb.stateLock.Lock()
defer rb.stateLock.Unlock()
if rb.state <= stopped {
if rb.state <= stopping {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still relies upon enum ordering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This affect the ring buffer states and lock. I wanted to edit that on another PR and not on this one.

Comment thread manager.go
switch m.state {
case reset, elfLoaded:
return ErrManagerNotInitialized
case initialized, stopping, paused, running:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's stopping, it shouldn't stop again

@theop-dd theop-dd Sep 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stopping is only a window, not a terminal state.

stopReaders sets it before dropping the lock (so Start/NewPerfRing/NewRingBuffer cannot add readers while we Wait), then restores the previous state before returning — unless a concurrent Stop() already moved the manager to reset. That way StopReaders() does not leave the manager stuck in stopping.

Stop() still accepts stopping for the concurrent case: a Stop() that arrives during that unlock window. After StopReaders() returns, state is restored, so the usual StopReaders() then Stop() sequence sees initialized/paused/running again. closeReader is idempotent if the readers were already shut down.

@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot merged commit 5f46a78 into main Sep 17, 2026
4 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854d Bot deleted the theop-dd/fix-panic-update-probes branch September 17, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants