Go version
go version go1.24.1 linux/amd64
What did you do?
Using defer wg.Done()
is dangerous, as the caller of wg.Wait() might get scheduled before the panic has a chance to complete.
https://go.dev/play/p/bd3XS0jWlxh
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
panic("test")
}()
wg.Wait()
os.Exit(0)
}
Other scenarios can be that the caller of wg.Wait
expects a resource/variable to be initialized and panicking when it isn't: https://go.dev/play/p/5tA0oEmAKSe, thus hiding the original panic/root problem.
What did you see happen?
The program can exit 0 (~3% of the time on my machine).
What did you expect to see?
People should ~never use defer wg.Done()
, as this should never exit(0).
Comment From: gopherbot
Change https://go.dev/cl/689455 mentions this issue: sync: WaitGroup.Go: Don't call wg.Done() when panicking
Comment From: seankhliao
see https://github.com/golang/go/issues/63796#issuecomment-2825614606
We should never promise to panic.
Comment From: Jille
Your argument (which I disagree with, but let's discuss that in the CL) only applies to sync.WaitGroup.Do(). I wanted to talk about all (other) code doing defer wg.Done()
in this issue.
Comment From: TapirLiu
Even if it is a problem, it is not the fault of wg.Done
.
package main
import "sync"
import "os"
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer func() { select{} }()
defer wg.Done()
panic("test")
}()
wg.Wait()
os.Exit(0)
}