diff options
author | Joe Tsai <joetsai@digital-static.net> | 2020-06-08 16:37:31 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-08 16:37:31 -0700 |
commit | 11c4583a280337c7ac34c591b4321552981a7cc0 (patch) | |
tree | 665edc6d6efa7416baba1daa03dfb819c41da76a /cmp/compare.go | |
parent | 1776240f8f841dfa00cb72d811301dbb0298f983 (diff) | |
download | go-cmp-11c4583a280337c7ac34c591b4321552981a7cc0.tar.gz |
Avoid leaking implementation details of the exporter (#206)
The current implementation for forcibly exporting fields relies on
the reflect.Value.Addr method for the parent struct value,
where it copies a non-addressable struct onto to the heap so
that it is addressable. However, this action leaks a subtle detail
of how the internal implementation works since the accessed field
for within a struct is only addressable if and only if the
parent struct is also addressable.
Modify the implementation to avoid leaking this implementation detail
by shallow copying the accessed unexported field to remove any
notion of addressability if the parent struct is also unaddressable.
Fixes #181
Diffstat (limited to 'cmp/compare.go')
-rw-r--r-- | cmp/compare.go | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/cmp/compare.go b/cmp/compare.go index a58ada5..c82c062 100644 --- a/cmp/compare.go +++ b/cmp/compare.go @@ -386,6 +386,7 @@ func sanitizeValue(v reflect.Value, t reflect.Type) reflect.Value { } func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { + var addr bool var vax, vay reflect.Value // Addressable versions of vx and vy var mayForce, mayForceInit bool @@ -407,6 +408,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { // For retrieveUnexportedField to work, the parent struct must // be addressable. Create a new copy of the values if // necessary to make them addressable. + addr = vx.CanAddr() || vy.CanAddr() vax = makeAddressable(vx) vay = makeAddressable(vy) } @@ -417,6 +419,7 @@ func (s *state) compareStruct(t reflect.Type, vx, vy reflect.Value) { mayForceInit = true } step.mayForce = mayForce + step.paddr = addr step.pvx = vax step.pvy = vay step.field = t.Field(i) |