Defer/Go with Panic/Recover

ID

go.defer_go_panic_recover

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Go

Tags

reliability, suspicious

Description

Reports panic or recover used directly as the function of a defer or go statement: defer panic(…​), go recover(), defer recover() and go panic(…​).

Rationale

recover only stops a panic when it is called directly by a deferred function; deferring it or running it in a new goroutine means it executes in the wrong frame and always returns nil, recovering nothing. A panic started in its own goroutine (go panic(…​)) cannot be recovered by the spawning goroutine and crashes the whole program, and a deferred panic fires unconditionally as the function unwinds. Wrapping the builtin in a closure (defer func(){ recover() }()) is the correct idiom and is not reported.

defer panic("boom") // FLAW — panic fires unconditionally on unwind
go recover()        // FLAW — runs in another goroutine, recovers nothing

defer func() { // OK — recover called directly by the deferred function
    if r := recover(); r != nil {
        cleanup()
    }
}()

Remediation

Recover inside a deferred function literal: defer func() { if r := recover(); r != nil { …​ } }(). Do not defer or go a bare panic/recover.