Source File
bypass.go
Belonging Package
github.com/davecgh/go-spew/spew
// 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.4package spewimport ()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 uintptrvar (// 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.5ro: 1 << 5,addr: 1 << 7,}, {// Up to Go tip.ro: 1<<5 | 1<<6,addr: 1 << 8,}}var flagValOffset = func() uintptr {, := reflect.TypeOf(reflect.Value{}).FieldByName("flag")if ! {panic("reflect.Value has no flag field")}return .Offset}()// flagField returns a pointer to the flag field of a reflect.Value.func flagField( *reflect.Value) *flag {return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer()) + 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( reflect.Value) reflect.Value {if !.IsValid() || (.CanInterface() && .CanAddr()) {return}:= flagField(&)* &^= flagRO* |= flagAddrreturn}// Sanity checks against future reflect package changes// to the type or semantics of the Value.flag field.func init() {, := reflect.TypeOf(reflect.Value{}).FieldByName("flag")if ! {panic("reflect.Value has no flag field")}if .Type.Kind() != reflect.TypeOf(flag(0)).Kind() {panic("reflect.Value flag field has changed kind")}type intvar struct {// t0 will have flagEmbedRO set.// a will have flagStickyRO set}:= reflect.ValueOf().FieldByName("A"):= reflect.ValueOf().FieldByName("a"):= reflect.ValueOf().FieldByName("t0")// Infer flagRO from the difference between the flags// for the (otherwise identical) fields in t.:= *flagField(&):= *flagField(&) | *flagField(&)flagRO = ^// Infer flagAddr from the difference between a value// taken from a pointer and not.:= reflect.ValueOf(&).Elem().FieldByName("A"):= *flagField(&):= *flagField(&)flagAddr = ^// Check that the inferred flags tally with one of the known versions.for , := range okFlags {if flagRO == .ro && flagAddr == .addr {return}}panic("reflect.Value read-only flag has changed semantics")}
![]() |
The pages are generated with Golds v0.8.2. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |