bypass.go raw

   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