diff options
| -rw-r--r-- | spew/common.go | 52 | ||||
| -rw-r--r-- | spew/internal_test.go | 3 | ||||
| -rw-r--r-- | test_coverage.txt | 57 |
3 files changed, 78 insertions, 34 deletions
diff --git a/spew/common.go b/spew/common.go index 0e59eca..bc26e7e 100644 --- a/spew/common.go +++ b/spew/common.go @@ -25,13 +25,55 @@ import ( "unsafe" ) -// reflectValue mirrors the struct layout of the reflect package Value type. -var reflectValue struct { +// offsetPtr, offsetScalar, and offsetFlag are the offsets for the internal +// reflect.Value fields. +var offsetPtr, offsetScalar, offsetFlag uintptr + +// reflectValueOld mirrors the struct layout of the reflect package Value type +// before golang commit ecccf07e7f9d. +var reflectValueOld struct { typ unsafe.Pointer val unsafe.Pointer flag uintptr } +// reflectValueNew mirrors the struct layout of the reflect package Value type +// after golang commit ecccf07e7f9d. +var reflectValueNew struct { + typ unsafe.Pointer + ptr unsafe.Pointer + scalar uintptr + flag uintptr +} + +func init() { + // Older versions of reflect.Value stored small integers directly in the + // ptr field (which is named val in the older versions). Newer versions + // added a new field named scalar for this purpose which unfortuantely + // comes before the flag field. Further the new field is before the + // flag field, so the offset of the flag field is different as well. + // This code constructs a new reflect.Value from a known small integer + // and checks if the val field within it matches. When it matches, the + // old style reflect.Value is being used. Otherwise it's the new style. + v := 0xf00 + vv := reflect.ValueOf(v) + upv := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + + unsafe.Offsetof(reflectValueOld.val)) + + // Assume the old style by default. + offsetPtr = unsafe.Offsetof(reflectValueOld.val) + offsetScalar = 0 + offsetFlag = unsafe.Offsetof(reflectValueOld.flag) + + // Use the new style offsets if the ptr field doesn't match the value + // since it must be in the new scalar field. + if int(*(*uintptr)(upv)) != v { + offsetPtr = unsafe.Offsetof(reflectValueNew.ptr) + offsetScalar = unsafe.Offsetof(reflectValueNew.scalar) + offsetFlag = unsafe.Offsetof(reflectValueNew.flag) + } +} + // flagIndir indicates whether the value field of a reflect.Value is the actual // data or a pointer to the data. const flagIndir = 1 << 1 @@ -48,11 +90,13 @@ const flagIndir = 1 << 1 func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { indirects := 1 vt := v.Type() - upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.val)) - rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + unsafe.Offsetof(reflectValue.flag))) + upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) + rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) if rvf&flagIndir != 0 { vt = reflect.PtrTo(v.Type()) indirects++ + } else if offsetScalar != 0 { + upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetScalar) } pv := reflect.NewAt(vt, upv) diff --git a/spew/internal_test.go b/spew/internal_test.go index d8c9761..faac638 100644 --- a/spew/internal_test.go +++ b/spew/internal_test.go @@ -92,8 +92,7 @@ const flagKindWidth = 5 // fallback code which punts to the standard fmt library for new types that // might get added to the language. func changeKind(v *reflect.Value, readOnly bool) { - rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + - unsafe.Offsetof(reflectValue.flag))) + rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) *rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift) if readOnly { *rvf |= flagRO diff --git a/test_coverage.txt b/test_coverage.txt index 37567db..2cd087a 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -6,48 +6,40 @@ github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44) github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39) github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30) github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18) +github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13) github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12) -github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (12/12) -github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11) github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11) +github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11) +github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10) github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9) github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8) github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7) github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5) -github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4) +github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4) github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4) github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4) -github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4) +github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4) +github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3) github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3) -github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3) +github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3) github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3) +github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3) github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3) -github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3) -github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3) -github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1) -github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1) -github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1) -github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1) -github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1) -github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1) github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1) +github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1) @@ -56,5 +48,14 @@ github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1) github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1) -github.com/davecgh/go-spew/spew ------------------------------- 100.00% (494/494) +github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1) +github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1) +github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1) +github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1) +github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1) +github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505) |
