github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/test/go-spew/spew/bypass.go (about)

     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  // +build !js,!appengine,!safe,!disableunsafe
    20  
    21  package spew
    22  
    23  import (
    24  	"reflect"
    25  	"unsafe"
    26  )
    27  
    28  const (
    29  	// UnsafeDisabled is a build-time constant which specifies whether or
    30  	// not access to the unsafe package is available.
    31  	UnsafeDisabled = false
    32  
    33  	// ptrSize is the size of a pointer on the current arch.
    34  	ptrSize = unsafe.Sizeof((*byte)(nil))
    35  )
    36  
    37  var (
    38  	// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
    39  	// internal reflect.Value fields.  These values are valid before golang
    40  	// commit ecccf07e7f9d which changed the format.  The are also valid
    41  	// after commit 82f48826c6c7 which changed the format again to mirror
    42  	// the original format.  Code in the init function updates these offsets
    43  	// as necessary.
    44  	offsetPtr    = uintptr(ptrSize)
    45  	offsetScalar = uintptr(0)
    46  	offsetFlag   = uintptr(ptrSize * 2)
    47  
    48  	// flagKindWidth and flagKindShift indicate various bits that the
    49  	// reflect package uses internally to track kind information.
    50  	//
    51  	// flagRO indicates whether or not the value field of a reflect.Value is
    52  	// read-only.
    53  	//
    54  	// flagIndir indicates whether the value field of a reflect.Value is
    55  	// the actual data or a pointer to the data.
    56  	//
    57  	// These values are valid before golang commit 90a7c3c86944 which
    58  	// changed their positions.  Code in the init function updates these
    59  	// flags as necessary.
    60  	flagKindWidth = uintptr(5)
    61  	flagKindShift = uintptr(flagKindWidth - 1)
    62  	flagRO        = uintptr(1 << 0)
    63  	flagIndir     = uintptr(1 << 1)
    64  )
    65  
    66  func init() {
    67  	// Older versions of reflect.Value stored small integers directly in the
    68  	// ptr field (which is named val in the older versions).  Versions
    69  	// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
    70  	// scalar for this purpose which unfortunately came before the flag
    71  	// field, so the offset of the flag field is different for those
    72  	// versions.
    73  	//
    74  	// This code constructs a new reflect.Value from a known small integer
    75  	// and checks if the size of the reflect.Value struct indicates it has
    76  	// the scalar field. When it does, the offsets are updated accordingly.
    77  	vv := reflect.ValueOf(0xf00)
    78  	if unsafe.Sizeof(vv) == (ptrSize * 4) {
    79  		offsetScalar = ptrSize * 2
    80  		offsetFlag = ptrSize * 3
    81  	}
    82  
    83  	// Commit 90a7c3c86944 changed the flag positions such that the low
    84  	// order bits are the kind.  This code extracts the kind from the flags
    85  	// field and ensures it's the correct type.  When it's not, the flag
    86  	// order has been changed to the newer format, so the flags are updated
    87  	// accordingly.
    88  	upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
    89  	upfv := *(*uintptr)(upf)
    90  	flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
    91  	if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
    92  		flagKindShift = 0
    93  		flagRO = 1 << 5
    94  		flagIndir = 1 << 6
    95  
    96  		// Commit adf9b30e5594 modified the flags to separate the
    97  		// flagRO flag into two bits which specifies whether or not the
    98  		// field is embedded.  This causes flagIndir to move over a bit
    99  		// and means that flagRO is the combination of either of the
   100  		// original flagRO bit and the new bit.
   101  		//
   102  		// This code detects the change by extracting what used to be
   103  		// the indirect bit to ensure it's set.  When it's not, the flag
   104  		// order has been changed to the newer format, so the flags are
   105  		// updated accordingly.
   106  		if upfv&flagIndir == 0 {
   107  			flagRO = 3 << 5
   108  			flagIndir = 1 << 7
   109  		}
   110  	}
   111  }
   112  
   113  // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
   114  // the typical safety restrictions preventing access to unaddressable and
   115  // unexported data.  It works by digging the raw pointer to the underlying
   116  // value out of the protected value and generating a new unprotected (unsafe)
   117  // reflect.Value to it.
   118  //
   119  // This allows us to check for implementations of the Stringer and error
   120  // interfaces to be used for pretty printing ordinarily unaddressable and
   121  // inaccessible values such as unexported struct fields.
   122  func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
   123  	indirects := 1
   124  	vt := v.Type()
   125  	upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
   126  	rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
   127  	if rvf&flagIndir != 0 {
   128  		vt = reflect.PtrTo(v.Type())
   129  		indirects++
   130  	} else if offsetScalar != 0 {
   131  		// The value is in the scalar field when it's not one of the
   132  		// reference types.
   133  		switch vt.Kind() {
   134  		case reflect.Uintptr:
   135  		case reflect.Chan:
   136  		case reflect.Func:
   137  		case reflect.Map:
   138  		case reflect.Ptr:
   139  		case reflect.UnsafePointer:
   140  		default:
   141  			upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
   142  				offsetScalar)
   143  		}
   144  	}
   145  
   146  	pv := reflect.NewAt(vt, upv)
   147  	rv = pv
   148  	for i := 0; i < indirects; i++ {
   149  		rv = rv.Elem()
   150  	}
   151  	return rv
   152  }