Skip to content

Commit c2e7979

Browse files
cuishuanggopherbot
authored andcommitted
go/analysis/passes/modernize: fix the potential deadlock issues in bloop
For golang/go#75599 Change-Id: Ic8009f9a7bcbd8f76b47bf6831132aeb0cbee2f3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/711980 Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Alan Donovan <[email protected]> TryBot-Bypass: Alan Donovan <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent bea5215 commit c2e7979

File tree

3 files changed

+43
-9
lines changed

3 files changed

+43
-9
lines changed

go/analysis/passes/modernize/bloop.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ func enclosingFunc(c inspector.Cursor) (inspector.Cursor, bool) {
189189
// 2. The only b.N loop in that benchmark function
190190
// - b.Loop() can only be called once per benchmark execution
191191
// - Multiple calls result in "B.Loop called with timer stopped" error
192+
// - Multiple loops may have complex interdependencies that are hard to analyze
192193
func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
193194
// Find the enclosing benchmark function
194195
curFunc, ok := enclosingFunc(c)
@@ -205,17 +206,14 @@ func usesBenchmarkNOnce(c inspector.Cursor, info *types.Info) bool {
205206
return false
206207
}
207208

208-
// Count b.N references in this benchmark function
209+
// Count all b.N references in this benchmark function (including nested functions)
209210
bnRefCount := 0
210-
filter := []ast.Node{(*ast.SelectorExpr)(nil), (*ast.FuncLit)(nil)}
211+
filter := []ast.Node{(*ast.SelectorExpr)(nil)}
211212
curFunc.Inspect(filter, func(cur inspector.Cursor) bool {
212-
switch n := cur.Node().(type) {
213-
case *ast.FuncLit:
214-
return false // don't descend into nested function literals
215-
case *ast.SelectorExpr:
216-
if n.Sel.Name == "N" && typesinternal.IsPointerToNamed(info.TypeOf(n.X), "testing", "B") {
217-
bnRefCount++
218-
}
213+
sel := cur.Node().(*ast.SelectorExpr)
214+
if sel.Sel.Name == "N" &&
215+
typesinternal.IsPointerToNamed(info.TypeOf(sel.X), "testing", "B") {
216+
bnRefCount++
219217
}
220218
return true
221219
})

go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,21 @@ func BenchmarkI(b *testing.B) {
113113
for i := 0; i < b.N; i++ { // nope: b.N accessed more than once in benchmark
114114
}
115115
}
116+
117+
func BenchmarkJ(b *testing.B) {
118+
var wg sync.WaitGroup
119+
ch := make(chan int, 10)
120+
wg.Add(1)
121+
go func() {
122+
for i := 0; i < b.N; i++ {
123+
<-ch
124+
}
125+
wg.Done()
126+
}()
127+
b.ResetTimer()
128+
for i := 0; i < b.N; i++ { // nope: multiple b.N loops in same function
129+
ch <- i
130+
}
131+
b.StopTimer()
132+
wg.Wait()
133+
}

go/analysis/passes/modernize/testdata/src/bloop/bloop_test.go.golden

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,21 @@ func BenchmarkI(b *testing.B) {
111111
for i := 0; i < b.N; i++ { // nope: b.N accessed more than once in benchmark
112112
}
113113
}
114+
115+
func BenchmarkJ(b *testing.B) {
116+
var wg sync.WaitGroup
117+
ch := make(chan int, 10)
118+
wg.Add(1)
119+
go func() {
120+
for i := 0; i < b.N; i++ {
121+
<-ch
122+
}
123+
wg.Done()
124+
}()
125+
b.ResetTimer()
126+
for i := 0; i < b.N; i++ { // nope: multiple b.N loops in same function
127+
ch <- i
128+
}
129+
b.StopTimer()
130+
wg.Wait()
131+
}

0 commit comments

Comments
 (0)