gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

bypass.go (4715B)


      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 }