| 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