Does the recover in main protect this program?
Question 503MediumGo 1.22 to 1.25
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recovered", r)
}
}()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
var m map[string]int
m["x"] = 1 // panic in a goroutine
}()
wg.Wait()
fmt.Println("unreachable")
}
No. The whole process crashes with panic: assignment to entry in nil map and a goroutine trace. Panics unwind only the stack of the goroutine that panicked. If that goroutine has no recover of its own, the runtime ends the program, and deferred functions in other goroutines (including main's) never run.
Every goroutine that might panic, especially ones that run user or plugin code or request handlers, needs its own guard:
func safeGo(fn func()) {
go func() {
defer func() {
if r := recover(); r != nil {
log.Printf("panic: %v\n%s", r, debug.Stack())
}
}()
fn()
}()
}
net/http recovers panics per request for you, but a goroutine that a handler starts is not covered. Senior answer: recover at goroutine boundaries, log the stack, and turn the panic into an error. Do not quietly swallow it.
More on Tricky Output & Code-Review Puzzles
- Q501Code review: why does this timeout wrapper leak goroutines?
- Q502Which of these recover calls actually stop the panic?
- Q504A deferred function panics while another panic is in progress. What prints?
- Q505What does this integer puzzle print?
- Q506Why do these two floating-point comparisons give different results?
- Q507What does indexing and ranging over a UTF-8 string print?