Skip to content

Commit 5bd20b8

Browse files
committed
sync: repanic when f() panics for WaitGroup.Go
This is a copy-paste of #76126 (comment) by adonovan. Fixes #76126 Fixes #74702
1 parent 9f3a108 commit 5bd20b8

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package issue76126
2+
3+
import (
4+
"sync"
5+
"testing"
6+
)
7+
8+
func TestIssue76126(t *testing.T) {
9+
var wg sync.WaitGroup
10+
wg.Go(func() {
11+
panic("test")
12+
})
13+
wg.Wait()
14+
}

src/sync/waitgroup.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,18 @@ func (wg *WaitGroup) Wait() {
236236
func (wg *WaitGroup) Go(f func()) {
237237
wg.Add(1)
238238
go func() {
239-
defer wg.Done()
239+
defer func() {
240+
if x := recover(); x != nil {
241+
// Don't call Done as it may cause Wait to unblock,
242+
// so that the main goroutine races with the runtime.fatal
243+
// resulting from unhandled panic.
244+
panic(x)
245+
}
246+
247+
// f completed normally, or abruptly using goexit.
248+
// Either way, decrement the semaphore.
249+
wg.Done()
250+
}()
240251
f()
241252
}()
242253
}

src/sync/waitgroup_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
package sync_test
66

77
import (
8+
"internal/testenv"
9+
"os/exec"
10+
"path/filepath"
811
. "sync"
912
"sync/atomic"
1013
"testing"
@@ -110,6 +113,22 @@ func TestWaitGroupGo(t *testing.T) {
110113
}
111114
}
112115

116+
func TestIssue76126(t *testing.T) {
117+
testenv.MustHaveGoRun(t)
118+
119+
cmd := exec.Command(testenv.GoToolPath(t), "test", "-race")
120+
cmd.Dir = filepath.Join("testdata", "issue76126")
121+
b, err := cmd.CombinedOutput()
122+
if err != nil {
123+
t.Fatalf("go test -race failed: %v\n%s", err, b)
124+
}
125+
if code := cmd.ProcessState.ExitCode(); code == 0 {
126+
t.Fatalf("expected non-zero exit code, got %d", code)
127+
}
128+
129+
// Should fail with panic.
130+
}
131+
113132
func BenchmarkWaitGroupUncontended(b *testing.B) {
114133
type PaddedWaitGroup struct {
115134
WaitGroup

0 commit comments

Comments
 (0)