Update copystructure

Contains race fix
This commit is contained in:
James Bardin 2016-09-16 15:59:16 -04:00
parent 16e3a11da3
commit 733e5ab6bb
2 changed files with 23 additions and 15 deletions

View File

@ -1,6 +1,7 @@
package copystructure package copystructure
import ( import (
"errors"
"reflect" "reflect"
"sync" "sync"
@ -27,6 +28,8 @@ type CopierFunc func(interface{}) (interface{}, error)
// this map as well as to Copy in a mutex. // this map as well as to Copy in a mutex.
var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc) var Copiers map[reflect.Type]CopierFunc = make(map[reflect.Type]CopierFunc)
var errPointerRequired = errors.New("Copy argument must be a pointer when Lock is true")
type Config struct { type Config struct {
// Lock any types that are a sync.Locker and are not a mutex while copying. // Lock any types that are a sync.Locker and are not a mutex while copying.
// If there is an RLocker method, use that to get the sync.Locker. // If there is an RLocker method, use that to get the sync.Locker.
@ -38,6 +41,10 @@ type Config struct {
} }
func (c Config) Copy(v interface{}) (interface{}, error) { func (c Config) Copy(v interface{}) (interface{}, error) {
if c.Lock && reflect.ValueOf(v).Kind() != reflect.Ptr {
return nil, errPointerRequired
}
w := new(walker) w := new(walker)
if c.Lock { if c.Lock {
w.useLocks = true w.useLocks = true
@ -350,19 +357,20 @@ func (w *walker) lock(v reflect.Value) {
var locker sync.Locker var locker sync.Locker
// first check if we can get a locker from the value // We can't call Interface() on a value directly, since that requires
switch l := v.Interface().(type) { // a copy. This is OK, since the pointer to a value which is a sync.Locker
case rlocker: // is also a sync.Locker.
// don't lock a mutex directly if v.Kind() == reflect.Ptr {
if _, ok := l.(*sync.RWMutex); !ok { switch l := v.Interface().(type) {
locker = l.RLocker() case rlocker:
// don't lock a mutex directly
if _, ok := l.(*sync.RWMutex); !ok {
locker = l.RLocker()
}
case sync.Locker:
locker = l
} }
case sync.Locker: } else if v.CanAddr() {
locker = l
}
// the value itself isn't a locker, so check the method on a pointer too
if locker == nil && v.CanAddr() {
switch l := v.Addr().Interface().(type) { switch l := v.Addr().Interface().(type) {
case rlocker: case rlocker:
// don't lock a mutex directly // don't lock a mutex directly

6
vendor/vendor.json vendored
View File

@ -1484,10 +1484,10 @@
"revision": "8631ce90f28644f54aeedcb3e389a85174e067d1" "revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"
}, },
{ {
"checksumSHA1": "y2HsVMt3eYGqywv5ljijnywJMb4=", "checksumSHA1": "Vfkp+PcZ1wZ4+D6AsHTpKkdsQG0=",
"path": "github.com/mitchellh/copystructure", "path": "github.com/mitchellh/copystructure",
"revision": "6871c41ca9148d368715dedcda473f396f205df5", "revision": "501dcbdc7c358c4d0bfa066018834bedca79fde3",
"revisionTime": "2016-08-25T20:45:07Z" "revisionTime": "2016-09-16T19:51:24Z"
}, },
{ {
"path": "github.com/mitchellh/go-homedir", "path": "github.com/mitchellh/go-homedir",