Skip to content

Commit 8b3194a

Browse files
JayNakranimdempsky
authored andcommitted
cmd/compile: fix code duplication in race-instrumentation
instrumentnode() accidentally copies parent's already-instrumented nodes into child's Ninit block. This generates repeated code in race-instrumentation. This case surfaces only when it duplicates inline-labels, because of compile time error. In other cases, it silently generates incorrect instrumented code. This change prevents it from doing so. Fixes #17449. Change-Id: Icddf2198990442166307e176b7e20aa0cf6c171c Reviewed-on: https://go-review.googlesource.com/31317 Reviewed-by: Matthew Dempsky <[email protected]> Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 2b687a7 commit 8b3194a

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

src/cmd/compile/internal/gc/racewalk.go

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -145,36 +145,21 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
145145
goto ret
146146

147147
case OBLOCK:
148-
var out []*Node
149148
ls := n.List.Slice()
150-
for i := 0; i < len(ls); i++ {
151-
switch ls[i].Op {
152-
case OCALLFUNC, OCALLMETH, OCALLINTER:
153-
instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
154-
out = append(out, ls[i])
155-
// Scan past OAS nodes copying results off stack.
156-
// Those must not be instrumented, because the
157-
// instrumentation calls will smash the results.
158-
// The assignments are to temporaries, so they cannot
159-
// be involved in races and need not be instrumented.
160-
for i+1 < len(ls) && ls[i+1].Op == OAS && iscallret(ls[i+1].Right) {
161-
i++
162-
out = append(out, ls[i])
163-
}
164-
default:
165-
var outn Nodes
166-
outn.Set(out)
167-
instrumentnode(&ls[i], &outn, 0, 0)
168-
if ls[i].Op != OAS && ls[i].Op != OASWB && ls[i].Op != OAS2FUNC || ls[i].Ninit.Len() == 0 {
169-
out = append(outn.Slice(), ls[i])
170-
} else {
171-
// Splice outn onto end of ls[i].Ninit
172-
ls[i].Ninit.AppendNodes(&outn)
173-
out = append(out, ls[i])
174-
}
149+
afterCall := false
150+
for i := range ls {
151+
op := ls[i].Op
152+
// Scan past OAS nodes copying results off stack.
153+
// Those must not be instrumented, because the
154+
// instrumentation calls will smash the results.
155+
// The assignments are to temporaries, so they cannot
156+
// be involved in races and need not be instrumented.
157+
if afterCall && op == OAS && iscallret(ls[i].Right) {
158+
continue
175159
}
160+
instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
161+
afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
176162
}
177-
n.List.Set(out)
178163
goto ret
179164

180165
case ODEFER:

test/fixedbugs/issue17449.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// errorcheck -0 -race
2+
3+
// Copyright 2016 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
// Issue 17449: race instrumentation copies over previous instrumented nodes from parents block into child's Ninit block.
8+
// This code surfaces the duplication at compile time because of generated inline labels.
9+
10+
package master
11+
12+
type PriorityList struct {
13+
elems []interface{}
14+
}
15+
16+
func (x *PriorityList) Len() int { return len(x.elems) }
17+
18+
func (l *PriorityList) remove(i int) interface{} {
19+
elem := l.elems[i]
20+
l.elems = append(l.elems[:i], l.elems[i+1:]...)
21+
return elem
22+
}
23+
24+
func (l *PriorityList) Next() interface{} {
25+
return l.remove(l.Len() - 1)
26+
}
27+
28+
var l *PriorityList
29+
30+
func Foo() {
31+
// It would fail here if instrumented code (including inline-label) was copied.
32+
for elem := l.Next(); elem != nil; elem = l.Next() {
33+
}
34+
}

0 commit comments

Comments
 (0)