Compare commits

...

17 Commits

Author SHA1 Message Date
Jeff Carr 7c14bddce3 make test
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-01-14 12:58:17 -06:00
Jeff Carr a502f839a1 flatten paths
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-01-14 12:21:06 -06:00
Jeff Carr b71a36f214 add comments
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-01-14 12:03:26 -06:00
Jeff Carr 2856d50d00 clean go mod
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-01-14 11:49:34 -06:00
David Hill d8f796af33 travis: test against go 1.11 2018-08-30 15:11:38 -04:00
David Hill 8991bc29aa travis: test against go 1.10.x 2018-02-21 17:26:28 -06:00
Roger Peppe 87df7c60d5 simpler, more robust bypass
We make the bypass implementation a little simpler
by inferring the flag field position from available
reflect information and more robust by checking
that the flags that are set actually match the
semantics we expect.

We can restrict the use of unsafe to a single function: flagField.
2018-02-03 01:28:59 -06:00
David Hill db69d09d2c vet: fix vet warnings 2018-01-21 11:36:22 -05:00
Kevin Burke ecdeabc654 Add Go tip to coverage matrix
Also make this project compatible with running Travis CI on
forks - the go_import_path directive tells Travis to clone to
$GOPATH/src/github.com/davecgh/go-spew even if the remote user is
different.
2017-10-05 10:54:31 -05:00
Dave Collins dce690a33e
Update tests for cgo changes to Go tip. 2017-10-03 14:58:30 -05:00
David Hill a476722483 travis: test against go 1.9 2017-08-29 15:53:20 -04:00
David Hill adab96458c travis: test against 1.8.x 2017-07-11 14:34:51 -04:00
David Hill 9fadf46324 travis: Use gometalinter 2017-07-11 11:24:36 -05:00
Fabio Rapposelli e250ec7f59 Fix 'and/or' in the ISC license text 2017-07-11 11:23:18 -05:00
Andrew Keating d0f88dafcf Fix build, license, coverage, and godoc links 2017-07-11 11:21:44 -05:00
wangkechun a174e30547 Update common.go (#63) 2017-07-11 11:20:43 -05:00
Bill Q 782f4967f2 correct misspell on spew/common.go#L183 2017-06-27 02:16:45 +03:00
25 changed files with 223 additions and 199 deletions

3
.gitignore vendored
View File

@ -3,6 +3,9 @@
*.a *.a
*.so *.so
#test files
profile.cov
# Folders # Folders
_obj _obj
_test _test

View File

@ -1,14 +1,29 @@
language: go language: go
go_import_path: github.com/davecgh/go-spew
go: go:
- 1.5.4 - 1.6.x
- 1.6.3 - 1.7.x
- 1.7 - 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
sudo: false
install: install:
- go get -v golang.org/x/tools/cmd/cover - go get -v github.com/alecthomas/gometalinter
- gometalinter --install
script: script:
- go test -v -tags=safe ./spew - export PATH=$PATH:$HOME/gopath/bin
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov - export GORACE="halt_on_error=1"
- test -z "$(gometalinter --disable-all
--enable=gofmt
--enable=golint
--enable=vet
--enable=gosimple
--enable=unconvert
--deadline=4m ./spew | tee /dev/stderr)"
- go test -v -race -tags safe ./spew
- go test -v -race -tags testcgo ./spew -covermode=atomic -coverprofile=profile.cov
after_success: after_success:
- go get -v github.com/mattn/goveralls - go get -v github.com/mattn/goveralls
- export PATH=$PATH:$HOME/gopath/bin
- goveralls -coverprofile=profile.cov -service=travis-ci - goveralls -coverprofile=profile.cov -service=travis-ci

View File

@ -2,7 +2,7 @@ ISC License
Copyright (c) 2012-2016 Dave Collins <dave@davec.name> Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
Permission to use, copy, modify, and distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies. copyright notice and this permission notice appear in all copies.

16
Makefile Normal file
View File

@ -0,0 +1,16 @@
all:
@echo
@echo the github branch in this repo has the davecgh\'s master branch
@echo
@echo this is an experiement by me to learn how go modules and versioning works
@echo go-spew is a great tool. thanks dave!
@echo
test:
go test -v -race -tags safe ./
go test -v -race -tags testcgo ./ -covermode=atomic -coverprofile=profile.cov
redomod:
rm -f go.*
GO111MODULE= go mod init
GO111MODULE= go mod tidy

View File

@ -1,12 +1,9 @@
go-spew go-spew
======= =======
[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)] [![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)](https://travis-ci.org/davecgh/go-spew)
(https://travis-ci.org/davecgh/go-spew) [![ISC License] [![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status] [![Coverage Status](https://img.shields.io/coveralls/davecgh/go-spew.svg)](https://coveralls.io/r/davecgh/go-spew?branch=master)
(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
(https://coveralls.io/r/davecgh/go-spew?branch=master)
Go-spew implements a deep pretty printer for Go data structures to aid in Go-spew implements a deep pretty printer for Go data structures to aid in
debugging. A comprehensive suite of tests with 100% test coverage is provided debugging. A comprehensive suite of tests with 100% test coverage is provided
@ -21,8 +18,7 @@ post about it
## Documentation ## Documentation
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)] [![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/davecgh/go-spew/spew)
(http://godoc.org/github.com/davecgh/go-spew/spew)
Full `go doc` style documentation for the project can be viewed online without Full `go doc` style documentation for the project can be viewed online without
installing this package by using the excellent GoDoc site here: installing this package by using the excellent GoDoc site here:

145
bypass.go Normal file
View File

@ -0,0 +1,145 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// Go versions prior to 1.4 are disabled because they use a different layout
// for interfaces which make the implementation of unsafeReflectValue more complex.
// +build !js,!appengine,!safe,!disableunsafe,go1.4
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
type flag uintptr
var (
// flagRO indicates whether the value field of a reflect.Value
// is read-only.
flagRO flag
// flagAddr indicates whether the address of the reflect.Value's
// value may be taken.
flagAddr flag
)
// flagKindMask holds the bits that make up the kind
// part of the flags field. In all the supported versions,
// it is in the lower 5 bits.
const flagKindMask = flag(0x1f)
// Different versions of Go have used different
// bit layouts for the flags type. This table
// records the known combinations.
var okFlags = []struct {
ro, addr flag
}{{
// From Go 1.4 to 1.5
ro: 1 << 5,
addr: 1 << 7,
}, {
// Up to Go tip.
ro: 1<<5 | 1<<6,
addr: 1 << 8,
}}
var flagValOffset = func() uintptr {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
return field.Offset
}()
// flagField returns a pointer to the flag field of a reflect.Value.
func flagField(v *reflect.Value) *flag {
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) reflect.Value {
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
return v
}
flagFieldPtr := flagField(&v)
*flagFieldPtr &^= flagRO
*flagFieldPtr |= flagAddr
return v
}
// Sanity checks against future reflect package changes
// to the type or semantics of the Value.flag field.
func init() {
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
if !ok {
panic("reflect.Value has no flag field")
}
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
panic("reflect.Value flag field has changed kind")
}
type t0 int
var t struct {
A t0
// t0 will have flagEmbedRO set.
t0
// a will have flagStickyRO set
a t0
}
vA := reflect.ValueOf(t).FieldByName("A")
va := reflect.ValueOf(t).FieldByName("a")
vt0 := reflect.ValueOf(t).FieldByName("t0")
// Infer flagRO from the difference between the flags
// for the (otherwise identical) fields in t.
flagPublic := *flagField(&vA)
flagWithRO := *flagField(&va) | *flagField(&vt0)
flagRO = flagPublic ^ flagWithRO
// Infer flagAddr from the difference between a value
// taken from a pointer and not.
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
flagNoPtr := *flagField(&vA)
flagPtr := *flagField(&vPtrA)
flagAddr = flagNoPtr ^ flagPtr
// Check that the inferred flags tally with one of the known versions.
for _, f := range okFlags {
if flagRO == f.ro && flagAddr == f.addr {
return
}
}
panic("reflect.Value read-only flag has changed semantics")
}

View File

@ -16,7 +16,7 @@
// when the code is running on Google App Engine, compiled by GopherJS, or // when the code is running on Google App Engine, compiled by GopherJS, or
// "-tags safe" is added to the go build command line. The "disableunsafe" // "-tags safe" is added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used. // tag is deprecated and thus should not be used.
// +build js appengine safe disableunsafe // +build js appengine safe disableunsafe !go1.4
package spew package spew

View File

@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
w.Write(closeParenBytes) w.Write(closeParenBytes)
} }
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' // printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w. // prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) { func printHexPtr(w io.Writer, p uintptr) {
// Null pointer. // Null pointer.

View File

@ -21,7 +21,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/davecgh/go-spew/spew" "go.wit.com/dev/davecgh/spew"
) )
// custom type to test Stinger interface on non-pointer receiver. // custom type to test Stinger interface on non-pointer receiver.

View File

View File

@ -35,16 +35,16 @@ var (
// cCharRE is a regular expression that matches a cgo char. // cCharRE is a regular expression that matches a cgo char.
// It is used to detect character arrays to hexdump them. // It is used to detect character arrays to hexdump them.
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
// cUnsignedCharRE is a regular expression that matches a cgo unsigned // cUnsignedCharRE is a regular expression that matches a cgo unsigned
// char. It is used to detect unsigned character arrays to hexdump // char. It is used to detect unsigned character arrays to hexdump
// them. // them.
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
// cUint8tCharRE is a regular expression that matches a cgo uint8_t. // cUint8tCharRE is a regular expression that matches a cgo uint8_t.
// It is used to detect uint8_t arrays to hexdump them. // It is used to detect uint8_t arrays to hexdump them.
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
) )
// dumpState contains information about the state of a dump operation. // dumpState contains information about the state of a dump operation.
@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
// Display dereferenced value. // Display dereferenced value.
d.w.Write(openParenBytes) d.w.Write(openParenBytes)
switch { switch {
case nilFound == true: case nilFound:
d.w.Write(nilAngleBytes) d.w.Write(nilAngleBytes)
case cycleFound == true: case cycleFound:
d.w.Write(circularBytes) d.w.Write(circularBytes)
default: default:

View File

@ -67,7 +67,7 @@ import (
"testing" "testing"
"unsafe" "unsafe"
"github.com/davecgh/go-spew/spew" "go.wit.com/dev/davecgh/spew"
) )
// dumpTest is used to describe a test to be performed against the Dump method. // dumpTest is used to describe a test to be performed against the Dump method.
@ -768,7 +768,7 @@ func addUintptrDumpTests() {
func addUnsafePointerDumpTests() { func addUnsafePointerDumpTests() {
// Null pointer. // Null pointer.
v := unsafe.Pointer(uintptr(0)) v := unsafe.Pointer(nil)
nv := (*unsafe.Pointer)(nil) nv := (*unsafe.Pointer)(nil)
pv := &v pv := &v
vAddr := fmt.Sprintf("%p", pv) vAddr := fmt.Sprintf("%p", pv)

View File

@ -26,7 +26,7 @@ package spew_test
import ( import (
"fmt" "fmt"
"github.com/davecgh/go-spew/spew/testdata" "go.wit.com/dev/davecgh/spew/testdata"
) )
func addCgoDumpTests() { func addCgoDumpTests() {
@ -82,18 +82,20 @@ func addCgoDumpTests() {
v5Len := fmt.Sprintf("%d", v5l) v5Len := fmt.Sprintf("%d", v5l)
v5Cap := fmt.Sprintf("%d", v5c) v5Cap := fmt.Sprintf("%d", v5c)
v5t := "[6]testdata._Ctype_uint8_t" v5t := "[6]testdata._Ctype_uint8_t"
v5t2 := "[6]testdata._Ctype_uchar"
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
"{\n 00000000 74 65 73 74 35 00 " + "{\n 00000000 74 65 73 74 35 00 " +
" |test5.|\n}" " |test5.|\n}"
addDumpTest(v5, "("+v5t+") "+v5s+"\n") addDumpTest(v5, "("+v5t+") "+v5s+"\n", "("+v5t2+") "+v5s+"\n")
// C typedefed unsigned char array. // C typedefed unsigned char array.
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
v6Len := fmt.Sprintf("%d", v6l) v6Len := fmt.Sprintf("%d", v6l)
v6Cap := fmt.Sprintf("%d", v6c) v6Cap := fmt.Sprintf("%d", v6c)
v6t := "[6]testdata._Ctype_custom_uchar_t" v6t := "[6]testdata._Ctype_custom_uchar_t"
v6t2 := "[6]testdata._Ctype_uchar"
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
"{\n 00000000 74 65 73 74 36 00 " + "{\n 00000000 74 65 73 74 36 00 " +
" |test6.|\n}" " |test6.|\n}"
addDumpTest(v6, "("+v6t+") "+v6s+"\n") addDumpTest(v6, "("+v6t+") "+v6s+"\n", "("+v6t2+") "+v6s+"\n")
} }

View File

@ -19,7 +19,7 @@ package spew_test
import ( import (
"fmt" "fmt"
"github.com/davecgh/go-spew/spew" "go.wit.com/dev/davecgh/spew"
) )
type Flag int type Flag int

View File

@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
// Display dereferenced value. // Display dereferenced value.
switch { switch {
case nilFound == true: case nilFound:
f.fs.Write(nilAngleBytes) f.fs.Write(nilAngleBytes)
case cycleFound == true: case cycleFound:
f.fs.Write(circularShortBytes) f.fs.Write(circularShortBytes)
default: default:

View File

@ -72,7 +72,7 @@ import (
"testing" "testing"
"unsafe" "unsafe"
"github.com/davecgh/go-spew/spew" "go.wit.com/dev/davecgh/spew"
) )
// formatterTest is used to describe a test to be performed against NewFormatter. // formatterTest is used to describe a test to be performed against NewFormatter.
@ -1083,7 +1083,7 @@ func addUintptrFormatterTests() {
func addUnsafePointerFormatterTests() { func addUnsafePointerFormatterTests() {
// Null pointer. // Null pointer.
v := unsafe.Pointer(uintptr(0)) v := unsafe.Pointer(nil)
nv := (*unsafe.Pointer)(nil) nv := (*unsafe.Pointer)(nil)
pv := &v pv := &v
vAddr := fmt.Sprintf("%p", pv) vAddr := fmt.Sprintf("%p", pv)
@ -1536,14 +1536,14 @@ func TestPrintSortedKeys(t *testing.T) {
t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected)
} }
s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) s = cfg.Sprint(map[testStruct]int{{1}: 1, {3}: 3, {2}: 2})
expected = "map[ts.1:1 ts.2:2 ts.3:3]" expected = "map[ts.1:1 ts.2:2 ts.3:3]"
if s != expected { if s != expected {
t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected)
} }
if !spew.UnsafeDisabled { if !spew.UnsafeDisabled {
s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) s = cfg.Sprint(map[testStructP]int{{1}: 1, {3}: 3, {2}: 2})
expected = "map[ts.1:1 ts.2:2 ts.3:3]" expected = "map[ts.1:1 ts.2:2 ts.3:3]"
if s != expected { if s != expected {
t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected)

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module go.wit.com/dev/davecgh/spew
go 1.21.4

View File

@ -36,10 +36,7 @@ type dummyFmtState struct {
} }
func (dfs *dummyFmtState) Flag(f int) bool { func (dfs *dummyFmtState) Flag(f int) bool {
if f == int('+') { return f == int('+')
return true
}
return false
} }
func (dfs *dummyFmtState) Precision() (int, bool) { func (dfs *dummyFmtState) Precision() (int, bool) {

View File

@ -16,7 +16,7 @@
// when the code is not running on Google App Engine, compiled by GopherJS, and // when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe" // "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used. // tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe // +build !js,!appengine,!safe,!disableunsafe,go1.4
/* /*
This test file is part of the spew package rather than than the spew_test This test file is part of the spew package rather than than the spew_test
@ -30,7 +30,6 @@ import (
"bytes" "bytes"
"reflect" "reflect"
"testing" "testing"
"unsafe"
) )
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to // changeKind uses unsafe to intentionally change the kind of a reflect.Value to
@ -38,13 +37,13 @@ import (
// fallback code which punts to the standard fmt library for new types that // fallback code which punts to the standard fmt library for new types that
// might get added to the language. // might get added to the language.
func changeKind(v *reflect.Value, readOnly bool) { func changeKind(v *reflect.Value, readOnly bool) {
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag)) flags := flagField(v)
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
if readOnly { if readOnly {
*rvf |= flagRO *flags |= flagRO
} else { } else {
*rvf &= ^uintptr(flagRO) *flags &^= flagRO
} }
*flags |= flagKindMask
} }
// TestAddedReflectValue tests functionaly of the dump and formatter code which // TestAddedReflectValue tests functionaly of the dump and formatter code which

View File

@ -1,152 +0,0 @@
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// NOTE: Due to the following build constraints, this file will only be compiled
// when the code is not running on Google App Engine, compiled by GopherJS, and
// "-tags safe" is not added to the go build command line. The "disableunsafe"
// tag is deprecated and thus should not be used.
// +build !js,!appengine,!safe,!disableunsafe
package spew
import (
"reflect"
"unsafe"
)
const (
// UnsafeDisabled is a build-time constant which specifies whether or
// not access to the unsafe package is available.
UnsafeDisabled = false
// ptrSize is the size of a pointer on the current arch.
ptrSize = unsafe.Sizeof((*byte)(nil))
)
var (
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
// internal reflect.Value fields. These values are valid before golang
// commit ecccf07e7f9d which changed the format. The are also valid
// after commit 82f48826c6c7 which changed the format again to mirror
// the original format. Code in the init function updates these offsets
// as necessary.
offsetPtr = uintptr(ptrSize)
offsetScalar = uintptr(0)
offsetFlag = uintptr(ptrSize * 2)
// flagKindWidth and flagKindShift indicate various bits that the
// reflect package uses internally to track kind information.
//
// flagRO indicates whether or not the value field of a reflect.Value is
// read-only.
//
// flagIndir indicates whether the value field of a reflect.Value is
// the actual data or a pointer to the data.
//
// These values are valid before golang commit 90a7c3c86944 which
// changed their positions. Code in the init function updates these
// flags as necessary.
flagKindWidth = uintptr(5)
flagKindShift = uintptr(flagKindWidth - 1)
flagRO = uintptr(1 << 0)
flagIndir = uintptr(1 << 1)
)
func init() {
// Older versions of reflect.Value stored small integers directly in the
// ptr field (which is named val in the older versions). Versions
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
// scalar for this purpose which unfortunately came before the flag
// field, so the offset of the flag field is different for those
// versions.
//
// This code constructs a new reflect.Value from a known small integer
// and checks if the size of the reflect.Value struct indicates it has
// the scalar field. When it does, the offsets are updated accordingly.
vv := reflect.ValueOf(0xf00)
if unsafe.Sizeof(vv) == (ptrSize * 4) {
offsetScalar = ptrSize * 2
offsetFlag = ptrSize * 3
}
// Commit 90a7c3c86944 changed the flag positions such that the low
// order bits are the kind. This code extracts the kind from the flags
// field and ensures it's the correct type. When it's not, the flag
// order has been changed to the newer format, so the flags are updated
// accordingly.
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
upfv := *(*uintptr)(upf)
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
flagKindShift = 0
flagRO = 1 << 5
flagIndir = 1 << 6
// Commit adf9b30e5594 modified the flags to separate the
// flagRO flag into two bits which specifies whether or not the
// field is embedded. This causes flagIndir to move over a bit
// and means that flagRO is the combination of either of the
// original flagRO bit and the new bit.
//
// This code detects the change by extracting what used to be
// the indirect bit to ensure it's set. When it's not, the flag
// order has been changed to the newer format, so the flags are
// updated accordingly.
if upfv&flagIndir == 0 {
flagRO = 3 << 5
flagIndir = 1 << 7
}
}
}
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
// the typical safety restrictions preventing access to unaddressable and
// unexported data. It works by digging the raw pointer to the underlying
// value out of the protected value and generating a new unprotected (unsafe)
// reflect.Value to it.
//
// This allows us to check for implementations of the Stringer and error
// interfaces to be used for pretty printing ordinarily unaddressable and
// inaccessible values such as unexported struct fields.
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
indirects := 1
vt := v.Type()
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 {
// The value is in the scalar field when it's not one of the
// reference types.
switch vt.Kind() {
case reflect.Uintptr:
case reflect.Chan:
case reflect.Func:
case reflect.Map:
case reflect.Ptr:
case reflect.UnsafePointer:
default:
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
offsetScalar)
}
}
pv := reflect.NewAt(vt, upv)
rv = pv
for i := 0; i < indirects; i++ {
rv = rv.Elem()
}
return rv
}

View File

@ -23,7 +23,7 @@ import (
"os" "os"
"testing" "testing"
"github.com/davecgh/go-spew/spew" "go.wit.com/dev/davecgh/spew"
) )
// spewFunc is used to identify which public function of the spew package or // spewFunc is used to identify which public function of the spew package or