bypass.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (c) 2015 Dave Collins <[email protected]>
  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. // Commit adf9b30e5594 modified the flags to separate the
  86. // flagRO flag into two bits which specifies whether or not the
  87. // field is embedded. This causes flagIndir to move over a bit
  88. // and means that flagRO is the combination of either of the
  89. // original flagRO bit and the new bit.
  90. //
  91. // This code detects the change by extracting what used to be
  92. // the indirect bit to ensure it's set. When it's not, the flag
  93. // order has been changed to the newer format, so the flags are
  94. // updated accordingly.
  95. if upfv&flagIndir == 0 {
  96. flagRO = 3 << 5
  97. flagIndir = 1 << 7
  98. }
  99. }
  100. }
  101. // unsafeReflectValue converts the passed reflect.Value into a one that bypasses
  102. // the typical safety restrictions preventing access to unaddressable and
  103. // unexported data. It works by digging the raw pointer to the underlying
  104. // value out of the protected value and generating a new unprotected (unsafe)
  105. // reflect.Value to it.
  106. //
  107. // This allows us to check for implementations of the Stringer and error
  108. // interfaces to be used for pretty printing ordinarily unaddressable and
  109. // inaccessible values such as unexported struct fields.
  110. func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
  111. indirects := 1
  112. vt := v.Type()
  113. upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
  114. rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
  115. if rvf&flagIndir != 0 {
  116. vt = reflect.PtrTo(v.Type())
  117. indirects++
  118. } else if offsetScalar != 0 {
  119. // The value is in the scalar field when it's not one of the
  120. // reference types.
  121. switch vt.Kind() {
  122. case reflect.Uintptr:
  123. case reflect.Chan:
  124. case reflect.Func:
  125. case reflect.Map:
  126. case reflect.Ptr:
  127. case reflect.UnsafePointer:
  128. default:
  129. upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
  130. offsetScalar)
  131. }
  132. }
  133. pv := reflect.NewAt(vt, upv)
  134. rv = pv
  135. for i := 0; i < indirects; i++ {
  136. rv = rv.Elem()
  137. }
  138. return rv
  139. }