1 | // Copyright 2013 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | // This file contains tests for the copylock checker's |
6 | // function declaration analysis. |
7 | |
8 | package a |
9 | |
10 | import "sync" |
11 | |
12 | func OkFunc(*sync.Mutex) {} |
13 | func BadFunc(sync.Mutex) {} // want "BadFunc passes lock by value: sync.Mutex" |
14 | func BadFunc2(sync.Map) {} // want "BadFunc2 passes lock by value: sync.Map contains sync.Mutex" |
15 | func OkRet() *sync.Mutex {} |
16 | func BadRet() sync.Mutex {} // Don't warn about results |
17 | |
18 | var ( |
19 | OkClosure = func(*sync.Mutex) {} |
20 | BadClosure = func(sync.Mutex) {} // want "func passes lock by value: sync.Mutex" |
21 | BadClosure2 = func(sync.Map) {} // want "func passes lock by value: sync.Map contains sync.Mutex" |
22 | ) |
23 | |
24 | type EmbeddedRWMutex struct { |
25 | sync.RWMutex |
26 | } |
27 | |
28 | func (*EmbeddedRWMutex) OkMeth() {} |
29 | func (EmbeddedRWMutex) BadMeth() {} // want "BadMeth passes lock by value: a.EmbeddedRWMutex" |
30 | func OkFunc(e *EmbeddedRWMutex) {} |
31 | func BadFunc(EmbeddedRWMutex) {} // want "BadFunc passes lock by value: a.EmbeddedRWMutex" |
32 | func OkRet() *EmbeddedRWMutex {} |
33 | func BadRet() EmbeddedRWMutex {} // Don't warn about results |
34 | |
35 | type FieldMutex struct { |
36 | s sync.Mutex |
37 | } |
38 | |
39 | func (*FieldMutex) OkMeth() {} |
40 | func (FieldMutex) BadMeth() {} // want "BadMeth passes lock by value: a.FieldMutex contains sync.Mutex" |
41 | func OkFunc(*FieldMutex) {} |
42 | func BadFunc(FieldMutex, int) {} // want "BadFunc passes lock by value: a.FieldMutex contains sync.Mutex" |
43 | |
44 | type L0 struct { |
45 | L1 |
46 | } |
47 | |
48 | type L1 struct { |
49 | l L2 |
50 | } |
51 | |
52 | type L2 struct { |
53 | sync.Mutex |
54 | } |
55 | |
56 | func (*L0) Ok() {} |
57 | func (L0) Bad() {} // want "Bad passes lock by value: a.L0 contains a.L1 contains a.L2" |
58 | |
59 | type EmbeddedMutexPointer struct { |
60 | s *sync.Mutex // safe to copy this pointer |
61 | } |
62 | |
63 | func (*EmbeddedMutexPointer) Ok() {} |
64 | func (EmbeddedMutexPointer) AlsoOk() {} |
65 | func StillOk(EmbeddedMutexPointer) {} |
66 | func LookinGood() EmbeddedMutexPointer {} |
67 | |
68 | type EmbeddedLocker struct { |
69 | sync.Locker // safe to copy interface values |
70 | } |
71 | |
72 | func (*EmbeddedLocker) Ok() {} |
73 | func (EmbeddedLocker) AlsoOk() {} |
74 | |
75 | type CustomLock struct{} |
76 | |
77 | func (*CustomLock) Lock() {} |
78 | func (*CustomLock) Unlock() {} |
79 | |
80 | func Ok(*CustomLock) {} |
81 | func Bad(CustomLock) {} // want "Bad passes lock by value: a.CustomLock" |
82 | |
83 | // Passing lock values into interface function arguments |
84 | func FuncCallInterfaceArg(f func(a int, b interface{})) { |
85 | var m sync.Mutex |
86 | var t struct{ lock sync.Mutex } |
87 | |
88 | f(1, "foo") |
89 | f(2, &t) |
90 | f(3, &sync.Mutex{}) |
91 | f(4, m) // want "call of f copies lock value: sync.Mutex" |
92 | f(5, t) // want "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
93 | var fntab []func(t) |
94 | fntab[0](t) // want "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
95 | } |
96 | |
97 | // Returning lock via interface value |
98 | func ReturnViaInterface(x int) (int, interface{}) { |
99 | var m sync.Mutex |
100 | var t struct{ lock sync.Mutex } |
101 | |
102 | switch x % 4 { |
103 | case 0: |
104 | return 0, "qwe" |
105 | case 1: |
106 | return 1, &sync.Mutex{} |
107 | case 2: |
108 | return 2, m // want "return copies lock value: sync.Mutex" |
109 | default: |
110 | return 3, t // want "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
111 | } |
112 | } |
113 | |
114 | // Some cases that we don't warn about. |
115 | |
116 | func AcceptedCases() { |
117 | x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227) |
118 | x = BadRet() // function call on RHS is OK (#16227) |
119 | x = *OKRet() // indirection of function call on RHS is OK (#16227) |
120 | } |
121 | |
122 | // TODO: Unfortunate cases |
123 | |
124 | // Non-ideal error message: |
125 | // Since we're looking for Lock methods, sync.Once's underlying |
126 | // sync.Mutex gets called out, but without any reference to the sync.Once. |
127 | type LocalOnce sync.Once |
128 | |
129 | func (LocalOnce) Bad() {} // want `Bad passes lock by value: a.LocalOnce contains sync.\b.*` |
130 | |
131 | // False negative: |
132 | // LocalMutex doesn't have a Lock method. |
133 | // Nevertheless, it is probably a bad idea to pass it by value. |
134 | type LocalMutex sync.Mutex |
135 | |
136 | func (LocalMutex) Bad() {} // WANTED: An error here :( |
137 |
Members