@@ -98,7 +98,10 @@ func timeSleep(ns int64) {
98
98
t .arg = gp
99
99
tb := t .assignBucket ()
100
100
lock (& tb .lock )
101
- tb .addtimerLocked (t )
101
+ if ! tb .addtimerLocked (t ) {
102
+ unlock (& tb .lock )
103
+ badTimer ()
104
+ }
102
105
goparkunlock (& tb .lock , waitReasonSleep , traceEvGoSleep , 2 )
103
106
}
104
107
@@ -128,22 +131,29 @@ func goroutineReady(arg interface{}, seq uintptr) {
128
131
func addtimer (t * timer ) {
129
132
tb := t .assignBucket ()
130
133
lock (& tb .lock )
131
- tb .addtimerLocked (t )
134
+ ok := tb .addtimerLocked (t )
132
135
unlock (& tb .lock )
136
+ if ! ok {
137
+ badTimer ()
138
+ }
133
139
}
134
140
135
141
// Add a timer to the heap and start or kick timerproc if the new timer is
136
142
// earlier than any of the others.
137
143
// Timers are locked.
138
- func (tb * timersBucket ) addtimerLocked (t * timer ) {
144
+ // Returns whether all is well: false if the data structure is corrupt
145
+ // due to user-level races.
146
+ func (tb * timersBucket ) addtimerLocked (t * timer ) bool {
139
147
// when must never be negative; otherwise timerproc will overflow
140
148
// during its delta calculation and never expire other runtime timers.
141
149
if t .when < 0 {
142
150
t .when = 1 << 63 - 1
143
151
}
144
152
t .i = len (tb .t )
145
153
tb .t = append (tb .t , t )
146
- siftupTimer (tb .t , t .i )
154
+ if ! siftupTimer (tb .t , t .i ) {
155
+ return false
156
+ }
147
157
if t .i == 0 {
148
158
// siftup moved to top: new earliest deadline.
149
159
if tb .sleeping {
@@ -159,6 +169,7 @@ func (tb *timersBucket) addtimerLocked(t *timer) {
159
169
tb .created = true
160
170
go timerproc (tb )
161
171
}
172
+ return true
162
173
}
163
174
164
175
// Delete timer t from the heap.
@@ -191,11 +202,19 @@ func deltimer(t *timer) bool {
191
202
}
192
203
tb .t [last ] = nil
193
204
tb .t = tb .t [:last ]
205
+ ok := true
194
206
if i != last {
195
- siftupTimer (tb .t , i )
196
- siftdownTimer (tb .t , i )
207
+ if ! siftupTimer (tb .t , i ) {
208
+ ok = false
209
+ }
210
+ if ! siftdownTimer (tb .t , i ) {
211
+ ok = false
212
+ }
197
213
}
198
214
unlock (& tb .lock )
215
+ if ! ok {
216
+ badTimer ()
217
+ }
199
218
return true
200
219
}
201
220
@@ -219,10 +238,13 @@ func timerproc(tb *timersBucket) {
219
238
if delta > 0 {
220
239
break
221
240
}
241
+ ok := true
222
242
if t .period > 0 {
223
243
// leave in heap but adjust next time to fire
224
244
t .when += t .period * (1 + - delta / t .period )
225
- siftdownTimer (tb .t , 0 )
245
+ if ! siftdownTimer (tb .t , 0 ) {
246
+ ok = false
247
+ }
226
248
} else {
227
249
// remove from heap
228
250
last := len (tb .t ) - 1
@@ -233,14 +255,19 @@ func timerproc(tb *timersBucket) {
233
255
tb .t [last ] = nil
234
256
tb .t = tb .t [:last ]
235
257
if last > 0 {
236
- siftdownTimer (tb .t , 0 )
258
+ if ! siftdownTimer (tb .t , 0 ) {
259
+ ok = false
260
+ }
237
261
}
238
262
t .i = - 1 // mark as removed
239
263
}
240
264
f := t .f
241
265
arg := t .arg
242
266
seq := t .seq
243
267
unlock (& tb .lock )
268
+ if ! ok {
269
+ badTimer ()
270
+ }
244
271
if raceenabled {
245
272
raceacquire (unsafe .Pointer (t ))
246
273
}
@@ -326,8 +353,20 @@ func timeSleepUntil() int64 {
326
353
}
327
354
328
355
// Heap maintenance algorithms.
329
-
330
- func siftupTimer (t []* timer , i int ) {
356
+ // These algorithms check for slice index errors manually.
357
+ // Slice index error can happen if the program is using racy
358
+ // access to timers. We don't want to panic here, because
359
+ // it will cause the program to crash with a mysterious
360
+ // "panic holding locks" message. Instead, we panic while not
361
+ // holding a lock.
362
+ // The races can occur despite the bucket locks because assignBucket
363
+ // itself is called without locks, so racy calls can cause a timer to
364
+ // change buckets while executing these functions.
365
+
366
+ func siftupTimer (t []* timer , i int ) bool {
367
+ if i >= len (t ) {
368
+ return false
369
+ }
331
370
when := t [i ].when
332
371
tmp := t [i ]
333
372
for i > 0 {
@@ -343,10 +382,14 @@ func siftupTimer(t []*timer, i int) {
343
382
t [i ] = tmp
344
383
t [i ].i = i
345
384
}
385
+ return true
346
386
}
347
387
348
- func siftdownTimer (t []* timer , i int ) {
388
+ func siftdownTimer (t []* timer , i int ) bool {
349
389
n := len (t )
390
+ if i >= n {
391
+ return false
392
+ }
350
393
when := t [i ].when
351
394
tmp := t [i ]
352
395
for {
@@ -382,6 +425,15 @@ func siftdownTimer(t []*timer, i int) {
382
425
t [i ] = tmp
383
426
t [i ].i = i
384
427
}
428
+ return true
429
+ }
430
+
431
+ // badTimer is called if the timer data structures have been corrupted,
432
+ // presumably due to racy use by the program. We panic here rather than
433
+ // panicing due to invalid slice access while holding locks.
434
+ // See issue #25686.
435
+ func badTimer () {
436
+ panic (errorString ("racy use of timers" ))
385
437
}
386
438
387
439
// Entry points for net, time to call nanotime.
0 commit comments