Skip to content

Commit 9962e2c

Browse files
authored
p2p/tracker: fix crash in clean when tracker is stopped (#33940)
1 parent d318e8e commit 9962e2c

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

p2p/tracker/tracker.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ func (t *Tracker) clean() {
138138
t.lock.Lock()
139139
defer t.lock.Unlock()
140140

141+
if t.expire == nil {
142+
return // Tracker was stopped.
143+
}
144+
141145
// Expire anything within a certain threshold (might be no items at all if
142146
// we raced with the delivery)
143147
for t.expire.Len() > 0 {
@@ -162,14 +166,15 @@ func (t *Tracker) clean() {
162166
t.schedule()
163167
}
164168

165-
// schedule starts a timer to trigger on the expiration of the first network
166-
// packet.
169+
// schedule starts a timer to trigger on the expiration of the first network packet.
167170
func (t *Tracker) schedule() {
168171
if t.expire.Len() == 0 {
169172
t.wake = nil
170173
return
171174
}
172-
t.wake = time.AfterFunc(time.Until(t.pending[t.expire.Front().Value.(uint64)].time.Add(t.timeout)), t.clean)
175+
nextID := t.expire.Front().Value.(uint64)
176+
nextTime := t.pending[nextID].time
177+
t.wake = time.AfterFunc(time.Until(nextTime.Add(t.timeout)), t.clean)
173178
}
174179

175180
// Stop reclaims resources of the tracker.

p2p/tracker/tracker_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@ import (
2424
"github.com/ethereum/go-ethereum/p2p"
2525
)
2626

27+
// TestCleanAfterStop verifies that the clean method does not crash when called
28+
// after Stop. This can happen because clean is scheduled via time.AfterFunc and
29+
// may fire after Stop sets t.expire to nil.
30+
func TestCleanAfterStop(t *testing.T) {
31+
cap := p2p.Cap{Name: "test", Version: 1}
32+
timeout := 50 * time.Millisecond
33+
tr := New(cap, "peer1", timeout)
34+
35+
// Track a request to start the expiration timer.
36+
tr.Track(Request{ID: 1, ReqCode: 0x01, RespCode: 0x02, Size: 1})
37+
38+
// Stop the tracker, then wait for the timer to fire.
39+
tr.Stop()
40+
time.Sleep(timeout + 50*time.Millisecond)
41+
42+
// Also verify that calling clean directly after stop doesn't panic.
43+
tr.clean()
44+
}
45+
2746
// This checks that metrics gauges for pending requests are be decremented when a
2847
// Tracker is stopped.
2948
func TestMetricsOnStop(t *testing.T) {

0 commit comments

Comments
 (0)