summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spew/common.go52
-rw-r--r--spew/internal_test.go3
-rw-r--r--test_coverage.txt57
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)