bypass.go 5.0 KB

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