Skip to content

runtime: avoid scary crash from concurrent calls to time.Timer.Reset #25686

Closed
@eliasnaur

Description

@eliasnaur

What version of Go are you using (go version)?

go version devel +4bb649fba8 Wed May 23 12:26:19 2018 +0000 linux/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

linux/amd64

What did you do?

While debugging #25619 it took me a while to realize that the scary runtime crash

$ go run timer.go 
panic: (runtime.errorString) (0x46adc0,0x4d0dc0)
fatal error: panic holding locks

goroutine 20 [running]:
runtime.throw(0x47cb63, 0x13)
	/home/elias/dev/go-tip/src/runtime/panic.go:589 +0x6a fp=0xc000045e20 sp=0xc000045df0 pc=0x422f2a
panic(0x46adc0, 0x4d0dc0)
	/home/elias/dev/go-tip/src/runtime/panic.go:454 +0x3ab fp=0xc000045eb0 sp=0xc000045e20 pc=0x422c5b
runtime.panicindex()
	/home/elias/dev/go-tip/src/runtime/panic.go:28 +0x5e fp=0xc000045ed0 sp=0xc000045eb0 pc=0x4219be
runtime.siftupTimer(0xc0000ac000, 0x3, 0x4, 0x5)
	/home/elias/dev/go-tip/src/runtime/time.go:331 +0xe9 fp=0xc000045ee0 sp=0xc000045ed0 pc=0x43c929
runtime.(*timersBucket).addtimerLocked(0x4d63e0, 0xc000096008)
	/home/elias/dev/go-tip/src/runtime/time.go:146 +0xa6 fp=0xc000045f30 sp=0xc000045ee0 pc=0x43c0e6
runtime.addtimer(0xc000096008)
	/home/elias/dev/go-tip/src/runtime/time.go:131 +0x83 fp=0xc000045f60 sp=0xc000045f30 pc=0x43c013
time.startTimer(0xc000096008)
	/home/elias/dev/go-tip/src/runtime/time.go:111 +0x2b fp=0xc000045f78 sp=0xc000045f60 pc=0x43bf2b
time.(*Timer).Reset(0xc000096000, 0x1476b081e8000, 0x1)
	/home/elias/dev/go-tip/src/time/sleep.go:130 +0x81 fp=0xc000045fb0 sp=0xc000045f78 pc=0x455ed1
main.main.func1(0xc000096000)
	/home/elias/snot/timer.go:10 +0x3a fp=0xc000045fd8 sp=0xc000045fb0 pc=0x45ab1a
runtime.goexit()
	/home/elias/dev/go-tip/src/runtime/asm_amd64.s:1365 +0x1 fp=0xc000045fe0 sp=0xc000045fd8 pc=0x44a5b1
created by main.main
	/home/elias/snot/timer.go:8 +0x60

could be caused by simple misuse of time.Timer.Reset. The above crash was easily reproduced with the (incorrect) program

package main

import "time"

func main() {
    t := time.NewTimer(100 * time.Hour)
    for i := 0; i < 8; i++ {
        go func() {
            for {
                t.Reset(100 * time.Hour)
            }
        }()
    }
    select {}
}

What did you expect to see?

The detection of the concurrent use of time.Timer and a friendly crash, the same way concurrent accesses to map (sometimes) fail with a friendly error instead of corrupting memory.

What did you see instead?

A runtime crash "fatal error: panic holding locks", which lead me to believe that the Go runtime was at fault.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions