| // Copyright 2013 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // This file contains tests for the copylock checker's |
| // function declaration analysis. |
| |
| package testdata |
| |
| import "sync" |
| |
| func OkFunc(*sync.Mutex) {} |
| func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex" |
| func OkRet() *sync.Mutex {} |
| func BadRet() sync.Mutex {} // Don't warn about results |
| |
| var ( |
| OkClosure = func(*sync.Mutex) {} |
| BadClosure = func(sync.Mutex) {} // ERROR "func passes lock by value: sync.Mutex" |
| ) |
| |
| type EmbeddedRWMutex struct { |
| sync.RWMutex |
| } |
| |
| func (*EmbeddedRWMutex) OkMeth() {} |
| func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.EmbeddedRWMutex" |
| func OkFunc(e *EmbeddedRWMutex) {} |
| func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex" |
| func OkRet() *EmbeddedRWMutex {} |
| func BadRet() EmbeddedRWMutex {} // Don't warn about results |
| |
| type FieldMutex struct { |
| s sync.Mutex |
| } |
| |
| func (*FieldMutex) OkMeth() {} |
| func (FieldMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: testdata.FieldMutex contains sync.Mutex" |
| func OkFunc(*FieldMutex) {} |
| func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes lock by value: testdata.FieldMutex contains sync.Mutex" |
| |
| type L0 struct { |
| L1 |
| } |
| |
| type L1 struct { |
| l L2 |
| } |
| |
| type L2 struct { |
| sync.Mutex |
| } |
| |
| func (*L0) Ok() {} |
| func (L0) Bad() {} // ERROR "Bad passes lock by value: testdata.L0 contains testdata.L1 contains testdata.L2" |
| |
| type EmbeddedMutexPointer struct { |
| s *sync.Mutex // safe to copy this pointer |
| } |
| |
| func (*EmbeddedMutexPointer) Ok() {} |
| func (EmbeddedMutexPointer) AlsoOk() {} |
| func StillOk(EmbeddedMutexPointer) {} |
| func LookinGood() EmbeddedMutexPointer {} |
| |
| type EmbeddedLocker struct { |
| sync.Locker // safe to copy interface values |
| } |
| |
| func (*EmbeddedLocker) Ok() {} |
| func (EmbeddedLocker) AlsoOk() {} |
| |
| type CustomLock struct{} |
| |
| func (*CustomLock) Lock() {} |
| func (*CustomLock) Unlock() {} |
| |
| func Ok(*CustomLock) {} |
| func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock" |
| |
| // Passing lock values into interface function arguments |
| func FuncCallInterfaceArg(f func(a int, b interface{})) { |
| var m sync.Mutex |
| var t struct{ lock sync.Mutex } |
| |
| f(1, "foo") |
| f(2, &t) |
| f(3, &sync.Mutex{}) |
| f(4, m) // ERROR "call of f copies lock value: sync.Mutex" |
| f(5, t) // ERROR "call of f copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
| var fntab []func(t) |
| fntab[0](t) // ERROR "call of fntab.0. copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
| } |
| |
| // Returning lock via interface value |
| func ReturnViaInterface(x int) (int, interface{}) { |
| var m sync.Mutex |
| var t struct{ lock sync.Mutex } |
| |
| switch x % 4 { |
| case 0: |
| return 0, "qwe" |
| case 1: |
| return 1, &sync.Mutex{} |
| case 2: |
| return 2, m // ERROR "return copies lock value: sync.Mutex" |
| default: |
| return 3, t // ERROR "return copies lock value: struct.lock sync.Mutex. contains sync.Mutex" |
| } |
| } |
| |
| // Some cases that we don't warn about. |
| |
| func AcceptedCases() { |
| x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227) |
| x = BadRet() // function call on RHS is OK (#16227) |
| x = *OKRet() // indirection of function call on RHS is OK (#16227) |
| } |
| |
| // TODO: Unfortunate cases |
| |
| // Non-ideal error message: |
| // Since we're looking for Lock methods, sync.Once's underlying |
| // sync.Mutex gets called out, but without any reference to the sync.Once. |
| type LocalOnce sync.Once |
| |
| func (LocalOnce) Bad() {} // ERROR "Bad passes lock by value: testdata.LocalOnce contains sync.Mutex" |
| |
| // False negative: |
| // LocalMutex doesn't have a Lock method. |
| // Nevertheless, it is probably a bad idea to pass it by value. |
| type LocalMutex sync.Mutex |
| |
| func (LocalMutex) Bad() {} // WANTED: An error here :( |