bypass.go 5.7 KB

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