Skip to content

Commit c81a353

Browse files
valyalaianlancetaylor
authored andcommitted
cmd/vet: check sync.* types' copying
Embed noLock struct into the following types, so `go vet -copylocks` catches their copying additionally to types containing sync.Mutex: - sync.Cond - sync.WaitGroup - sync.Pool - atomic.Value Fixes #14582 Change-Id: Icb543ef5ad10524ad239a15eec8a9b334b0e0660 Reviewed-on: https://go-review.googlesource.com/22015 Reviewed-by: Russ Cox <[email protected]> Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 258a4c3 commit c81a353

File tree

7 files changed

+110
-1
lines changed

7 files changed

+110
-1
lines changed

src/cmd/vet/testdata/copylock.go

+73-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package testdata
22

3-
import "sync"
3+
import (
4+
"sync"
5+
"sync/atomic"
6+
)
47

58
func OkFunc() {
69
var x *sync.Mutex
@@ -66,3 +69,72 @@ func BadFunc() {
6669
new := func(interface{}) {}
6770
new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
6871
}
72+
73+
// SyncTypesCheck checks copying of sync.* types except sync.Mutex
74+
func SyncTypesCheck() {
75+
// sync.RWMutex copying
76+
var rwmuX sync.RWMutex
77+
var rwmuXX = sync.RWMutex{}
78+
rwmuX1 := new(sync.RWMutex)
79+
rwmuY := rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
80+
rwmuY = rwmuX // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
81+
var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
82+
rwmuP := &rwmuX
83+
rwmuZ := &sync.RWMutex{}
84+
85+
// sync.Cond copying
86+
var condX sync.Cond
87+
var condXX = sync.Cond{}
88+
condX1 := new(sync.Cond)
89+
condY := condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
90+
condY = condX // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
91+
var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
92+
condP := &condX
93+
condZ := &sync.Cond{
94+
L: &sync.Mutex{},
95+
}
96+
condZ = sync.NewCond(&sync.Mutex{})
97+
98+
// sync.WaitGroup copying
99+
var wgX sync.WaitGroup
100+
var wgXX = sync.WaitGroup{}
101+
wgX1 := new(sync.WaitGroup)
102+
wgY := wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
103+
wgY = wgX // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
104+
var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
105+
wgP := &wgX
106+
wgZ := &sync.WaitGroup{}
107+
108+
// sync.Pool copying
109+
var poolX sync.Pool
110+
var poolXX = sync.Pool{}
111+
poolX1 := new(sync.Pool)
112+
poolY := poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
113+
poolY = poolX // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
114+
var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
115+
poolP := &poolX
116+
poolZ := &sync.Pool{}
117+
118+
// sync.Once copying
119+
var onceX sync.Once
120+
var onceXX = sync.Once{}
121+
onceX1 := new(sync.Once)
122+
onceY := onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
123+
onceY = onceX // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
124+
var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
125+
onceP := &onceX
126+
onceZ := &sync.Once{}
127+
}
128+
129+
// AtomicTypesCheck checks copying of sync/atomic types
130+
func AtomicTypesCheck() {
131+
// atomic.Value copying
132+
var vX atomic.Value
133+
var vXX = atomic.Value{}
134+
vX1 := new(atomic.Value)
135+
vY := vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
136+
vY = vX // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
137+
var vYY = vX // ERROR "variable declaration copies lock value to vYY: sync/atomic.Value contains sync/atomic.noCopy"
138+
vP := &vX
139+
vZ := &atomic.Value{}
140+
}

src/sync/atomic/value.go

+14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import (
1212
// Values can be created as part of other data structures.
1313
// The zero value for a Value returns nil from Load.
1414
// Once Store has been called, a Value must not be copied.
15+
//
16+
// A Value must not be copied after first use.
1517
type Value struct {
18+
noCopy noCopy
19+
1620
v interface{}
1721
}
1822

@@ -83,3 +87,13 @@ func (v *Value) Store(x interface{}) {
8387
// Disable/enable preemption, implemented in runtime.
8488
func runtime_procPin()
8589
func runtime_procUnpin()
90+
91+
// noCopy may be embedded into structs which must not be copied
92+
// after the first use.
93+
//
94+
// See https://github.com/golang/go/issues/8005#issuecomment-190753527
95+
// for details.
96+
type noCopy struct{}
97+
98+
// Lock is a no-op used by -copylocks checker from `go vet`.
99+
func (*noCopy) Lock() {}

src/sync/cond.go

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
// A Cond can be created as part of other structures.
2121
// A Cond must not be copied after first use.
2222
type Cond struct {
23+
noCopy noCopy
24+
2325
// L is held while observing or changing the condition
2426
L Locker
2527

@@ -84,3 +86,13 @@ func (c *copyChecker) check() {
8486
panic("sync.Cond is copied")
8587
}
8688
}
89+
90+
// noCopy may be embedded into structs which must not be copied
91+
// after the first use.
92+
//
93+
// See https://github.com/golang/go/issues/8005#issuecomment-190753527
94+
// for details.
95+
type noCopy struct{}
96+
97+
// Lock is a no-op used by -copylocks checker from `go vet`.
98+
func (*noCopy) Lock() {}

src/sync/mutex.go

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
// A Mutex is a mutual exclusion lock.
2020
// Mutexes can be created as part of other structures;
2121
// the zero value for a Mutex is an unlocked mutex.
22+
//
23+
// A Mutex must not be copied after first use.
2224
type Mutex struct {
2325
state int32
2426
sema uint32

src/sync/pool.go

+3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ import (
4040
// that scenario. It is more efficient to have such objects implement their own
4141
// free list.
4242
//
43+
// A Pool must not be copied after first use.
4344
type Pool struct {
45+
noCopy noCopy
46+
4447
local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
4548
localSize uintptr // size of the local array
4649

src/sync/rwmutex.go

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
// RWMutexes can be created as part of other
1717
// structures; the zero value for a RWMutex is
1818
// an unlocked mutex.
19+
//
20+
// An RWMutex must not be copied after first use.
1921
type RWMutex struct {
2022
w Mutex // held if there are pending writers
2123
writerSem uint32 // semaphore for writers to wait for completing readers

src/sync/waitgroup.go

+4
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import (
1515
// goroutines to wait for. Then each of the goroutines
1616
// runs and calls Done when finished. At the same time,
1717
// Wait can be used to block until all goroutines have finished.
18+
//
19+
// A WaitGroup must not be copied after first use.
1820
type WaitGroup struct {
21+
noCopy noCopy
22+
1923
// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
2024
// 64-bit atomic operations require 64-bit alignment, but 32-bit
2125
// compilers do not ensure it. So we allocate 12 bytes and then use

0 commit comments

Comments
 (0)