...

Source file src/github.com/davecgh/go-spew/spew/bypass.go

Documentation: github.com/davecgh/go-spew/spew

     1  // Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
     2  //
     3  // Permission to use, copy, modify, and distribute this software for any
     4  // purpose with or without fee is hereby granted, provided that the above
     5  // copyright notice and this permission notice appear in all copies.
     6  //
     7  // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     8  // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    10  // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    11  // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    12  // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    13  // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    14  
    15  // NOTE: Due to the following build constraints, this file will only be compiled
    16  // when the code is not running on Google App Engine, compiled by GopherJS, and
    17  // "-tags safe" is not added to the go build command line.  The "disableunsafe"
    18  // tag is deprecated and thus should not be used.
    19  // Go versions prior to 1.4 are disabled because they use a different layout
    20  // for interfaces which make the implementation of unsafeReflectValue more complex.
    21  // +build !js,!appengine,!safe,!disableunsafe,go1.4
    22  
    23  package spew
    24  
    25  import (
    26  	"reflect"
    27  	"unsafe"
    28  )
    29  
    30  const (
    31  	// UnsafeDisabled is a build-time constant which specifies whether or
    32  	// not access to the unsafe package is available.
    33  	UnsafeDisabled = false
    34  
    35  	// ptrSize is the size of a pointer on the current arch.
    36  	ptrSize = unsafe.Sizeof((*byte)(nil))
    37  )
    38  
    39  type flag uintptr
    40  
    41  var (
    42  	// flagRO indicates whether the value field of a reflect.Value
    43  	// is read-only.
    44  	flagRO flag
    45  
    46  	// flagAddr indicates whether the address of the reflect.Value's
    47  	// value may be taken.
    48  	flagAddr flag
    49  )
    50  
    51  // flagKindMask holds the bits that make up the kind
    52  // part of the flags field. In all the supported versions,
    53  // it is in the lower 5 bits.
    54  const flagKindMask = flag(0x1f)
    55  
    56  // Different versions of Go have used different
    57  // bit layouts for the flags type. This table
    58  // records the known combinations.
    59  var okFlags = []struct {
    60  	ro, addr flag
    61  }{{
    62  	// From Go 1.4 to 1.5
    63  	ro:   1 << 5,
    64  	addr: 1 << 7,
    65  }, {
    66  	// Up to Go tip.
    67  	ro:   1<<5 | 1<<6,
    68  	addr: 1 << 8,
    69  }}
    70  
    71  var flagValOffset = func() uintptr {
    72  	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
    73  	if !ok {
    74  		panic("reflect.Value has no flag field")
    75  	}
    76  	return field.Offset
    77  }()
    78  
    79  // flagField returns a pointer to the flag field of a reflect.Value.
    80  func flagField(v *reflect.Value) *flag {
    81  	return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
    82  }
    83  
    84  // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
    85  // the typical safety restrictions preventing access to unaddressable and
    86  // unexported data.  It works by digging the raw pointer to the underlying
    87  // value out of the protected value and generating a new unprotected (unsafe)
    88  // reflect.Value to it.
    89  //
    90  // This allows us to check for implementations of the Stringer and error
    91  // interfaces to be used for pretty printing ordinarily unaddressable and
    92  // inaccessible values such as unexported struct fields.
    93  func unsafeReflectValue(v reflect.Value) reflect.Value {
    94  	if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
    95  		return v
    96  	}
    97  	flagFieldPtr := flagField(&v)
    98  	*flagFieldPtr &^= flagRO
    99  	*flagFieldPtr |= flagAddr
   100  	return v
   101  }
   102  
   103  // Sanity checks against future reflect package changes
   104  // to the type or semantics of the Value.flag field.
   105  func init() {
   106  	field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
   107  	if !ok {
   108  		panic("reflect.Value has no flag field")
   109  	}
   110  	if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
   111  		panic("reflect.Value flag field has changed kind")
   112  	}
   113  	type t0 int
   114  	var t struct {
   115  		A t0
   116  		// t0 will have flagEmbedRO set.
   117  		t0
   118  		// a will have flagStickyRO set
   119  		a t0
   120  	}
   121  	vA := reflect.ValueOf(t).FieldByName("A")
   122  	va := reflect.ValueOf(t).FieldByName("a")
   123  	vt0 := reflect.ValueOf(t).FieldByName("t0")
   124  
   125  	// Infer flagRO from the difference between the flags
   126  	// for the (otherwise identical) fields in t.
   127  	flagPublic := *flagField(&vA)
   128  	flagWithRO := *flagField(&va) | *flagField(&vt0)
   129  	flagRO = flagPublic ^ flagWithRO
   130  
   131  	// Infer flagAddr from the difference between a value
   132  	// taken from a pointer and not.
   133  	vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
   134  	flagNoPtr := *flagField(&vA)
   135  	flagPtr := *flagField(&vPtrA)
   136  	flagAddr = flagNoPtr ^ flagPtr
   137  
   138  	// Check that the inferred flags tally with one of the known versions.
   139  	for _, f := range okFlags {
   140  		if flagRO == f.ro && flagAddr == f.addr {
   141  			return
   142  		}
   143  	}
   144  	panic("reflect.Value read-only flag has changed semantics")
   145  }
   146  

View as plain text