You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
13 KiB

  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package pointer
  5. // This package defines the treatment of intrinsics, i.e. library
  6. // functions requiring special analytical treatment.
  7. //
  8. // Most of these are C or assembly functions, but even some Go
  9. // functions require may special treatment if the analysis completely
  10. // replaces the implementation of an API such as reflection.
  11. // TODO(adonovan): support a means of writing analytic summaries in
  12. // the target code, so that users can summarise the effects of their
  13. // own C functions using a snippet of Go.
  14. import (
  15. "fmt"
  16. "go/types"
  17. "golang.org/x/tools/go/ssa"
  18. )
  19. // Instances of 'intrinsic' generate analysis constraints for calls to
  20. // intrinsic functions.
  21. // Implementations may exploit information from the calling site
  22. // via cgn.callersite; for shared contours this is nil.
  23. type intrinsic func(a *analysis, cgn *cgnode)
  24. // Initialized in explicit init() to defeat (spurious) initialization
  25. // cycle error.
  26. var intrinsicsByName = make(map[string]intrinsic)
  27. func init() {
  28. // Key strings are from Function.String().
  29. // That little dot ۰ is an Arabic zero numeral (U+06F0),
  30. // categories [Nd].
  31. for name, fn := range map[string]intrinsic{
  32. // Other packages.
  33. "bytes.Equal": ext۰NoEffect,
  34. "bytes.IndexByte": ext۰NoEffect,
  35. "crypto/aes.decryptBlockAsm": ext۰NoEffect,
  36. "crypto/aes.encryptBlockAsm": ext۰NoEffect,
  37. "crypto/aes.expandKeyAsm": ext۰NoEffect,
  38. "crypto/aes.hasAsm": ext۰NoEffect,
  39. "crypto/md5.block": ext۰NoEffect,
  40. "crypto/rc4.xorKeyStream": ext۰NoEffect,
  41. "crypto/sha1.block": ext۰NoEffect,
  42. "crypto/sha256.block": ext۰NoEffect,
  43. "hash/crc32.castagnoliSSE42": ext۰NoEffect,
  44. "hash/crc32.haveSSE42": ext۰NoEffect,
  45. "math.Abs": ext۰NoEffect,
  46. "math.Acos": ext۰NoEffect,
  47. "math.Asin": ext۰NoEffect,
  48. "math.Atan": ext۰NoEffect,
  49. "math.Atan2": ext۰NoEffect,
  50. "math.Ceil": ext۰NoEffect,
  51. "math.Cos": ext۰NoEffect,
  52. "math.Dim": ext۰NoEffect,
  53. "math.Exp": ext۰NoEffect,
  54. "math.Exp2": ext۰NoEffect,
  55. "math.Expm1": ext۰NoEffect,
  56. "math.Float32bits": ext۰NoEffect,
  57. "math.Float32frombits": ext۰NoEffect,
  58. "math.Float64bits": ext۰NoEffect,
  59. "math.Float64frombits": ext۰NoEffect,
  60. "math.Floor": ext۰NoEffect,
  61. "math.Frexp": ext۰NoEffect,
  62. "math.Hypot": ext۰NoEffect,
  63. "math.Ldexp": ext۰NoEffect,
  64. "math.Log": ext۰NoEffect,
  65. "math.Log10": ext۰NoEffect,
  66. "math.Log1p": ext۰NoEffect,
  67. "math.Log2": ext۰NoEffect,
  68. "math.Max": ext۰NoEffect,
  69. "math.Min": ext۰NoEffect,
  70. "math.Mod": ext۰NoEffect,
  71. "math.Modf": ext۰NoEffect,
  72. "math.Remainder": ext۰NoEffect,
  73. "math.Sin": ext۰NoEffect,
  74. "math.Sincos": ext۰NoEffect,
  75. "math.Sqrt": ext۰NoEffect,
  76. "math.Tan": ext۰NoEffect,
  77. "math.Trunc": ext۰NoEffect,
  78. "math/big.addMulVVW": ext۰NoEffect,
  79. "math/big.addVV": ext۰NoEffect,
  80. "math/big.addVW": ext۰NoEffect,
  81. "math/big.bitLen": ext۰NoEffect,
  82. "math/big.divWVW": ext۰NoEffect,
  83. "math/big.divWW": ext۰NoEffect,
  84. "math/big.mulAddVWW": ext۰NoEffect,
  85. "math/big.mulWW": ext۰NoEffect,
  86. "math/big.shlVU": ext۰NoEffect,
  87. "math/big.shrVU": ext۰NoEffect,
  88. "math/big.subVV": ext۰NoEffect,
  89. "math/big.subVW": ext۰NoEffect,
  90. "net.runtime_Semacquire": ext۰NoEffect,
  91. "net.runtime_Semrelease": ext۰NoEffect,
  92. "net.runtime_pollClose": ext۰NoEffect,
  93. "net.runtime_pollOpen": ext۰NoEffect,
  94. "net.runtime_pollReset": ext۰NoEffect,
  95. "net.runtime_pollServerInit": ext۰NoEffect,
  96. "net.runtime_pollSetDeadline": ext۰NoEffect,
  97. "net.runtime_pollUnblock": ext۰NoEffect,
  98. "net.runtime_pollWait": ext۰NoEffect,
  99. "net.runtime_pollWaitCanceled": ext۰NoEffect,
  100. "os.epipecheck": ext۰NoEffect,
  101. // All other runtime functions are treated as NoEffect.
  102. "runtime.SetFinalizer": ext۰runtime۰SetFinalizer,
  103. "strings.IndexByte": ext۰NoEffect,
  104. "sync.runtime_Semacquire": ext۰NoEffect,
  105. "sync.runtime_Semrelease": ext۰NoEffect,
  106. "sync.runtime_Syncsemacquire": ext۰NoEffect,
  107. "sync.runtime_Syncsemcheck": ext۰NoEffect,
  108. "sync.runtime_Syncsemrelease": ext۰NoEffect,
  109. "sync.runtime_procPin": ext۰NoEffect,
  110. "sync.runtime_procUnpin": ext۰NoEffect,
  111. "sync.runtime_registerPool": ext۰NoEffect,
  112. "sync/atomic.AddInt32": ext۰NoEffect,
  113. "sync/atomic.AddInt64": ext۰NoEffect,
  114. "sync/atomic.AddUint32": ext۰NoEffect,
  115. "sync/atomic.AddUint64": ext۰NoEffect,
  116. "sync/atomic.AddUintptr": ext۰NoEffect,
  117. "sync/atomic.CompareAndSwapInt32": ext۰NoEffect,
  118. "sync/atomic.CompareAndSwapUint32": ext۰NoEffect,
  119. "sync/atomic.CompareAndSwapUint64": ext۰NoEffect,
  120. "sync/atomic.CompareAndSwapUintptr": ext۰NoEffect,
  121. "sync/atomic.LoadInt32": ext۰NoEffect,
  122. "sync/atomic.LoadInt64": ext۰NoEffect,
  123. "sync/atomic.LoadPointer": ext۰NoEffect, // ignore unsafe.Pointers
  124. "sync/atomic.LoadUint32": ext۰NoEffect,
  125. "sync/atomic.LoadUint64": ext۰NoEffect,
  126. "sync/atomic.LoadUintptr": ext۰NoEffect,
  127. "sync/atomic.StoreInt32": ext۰NoEffect,
  128. "sync/atomic.StorePointer": ext۰NoEffect, // ignore unsafe.Pointers
  129. "sync/atomic.StoreUint32": ext۰NoEffect,
  130. "sync/atomic.StoreUintptr": ext۰NoEffect,
  131. "syscall.Close": ext۰NoEffect,
  132. "syscall.Exit": ext۰NoEffect,
  133. "syscall.Getpid": ext۰NoEffect,
  134. "syscall.Getwd": ext۰NoEffect,
  135. "syscall.Kill": ext۰NoEffect,
  136. "syscall.RawSyscall": ext۰NoEffect,
  137. "syscall.RawSyscall6": ext۰NoEffect,
  138. "syscall.Syscall": ext۰NoEffect,
  139. "syscall.Syscall6": ext۰NoEffect,
  140. "syscall.runtime_AfterFork": ext۰NoEffect,
  141. "syscall.runtime_BeforeFork": ext۰NoEffect,
  142. "syscall.setenv_c": ext۰NoEffect,
  143. "time.Sleep": ext۰NoEffect,
  144. "time.now": ext۰NoEffect,
  145. "time.startTimer": ext۰time۰startTimer,
  146. "time.stopTimer": ext۰NoEffect,
  147. } {
  148. intrinsicsByName[name] = fn
  149. }
  150. }
  151. // findIntrinsic returns the constraint generation function for an
  152. // intrinsic function fn, or nil if the function should be handled normally.
  153. //
  154. func (a *analysis) findIntrinsic(fn *ssa.Function) intrinsic {
  155. // Consult the *Function-keyed cache.
  156. // A cached nil indicates a normal non-intrinsic function.
  157. impl, ok := a.intrinsics[fn]
  158. if !ok {
  159. impl = intrinsicsByName[fn.String()] // may be nil
  160. if a.isReflect(fn) {
  161. if !a.config.Reflection {
  162. impl = ext۰NoEffect // reflection disabled
  163. } else if impl == nil {
  164. // Ensure all "reflect" code is treated intrinsically.
  165. impl = ext۰NotYetImplemented
  166. }
  167. } else if impl == nil && fn.Pkg != nil && fn.Pkg.Pkg.Path() == "runtime" {
  168. // Ignore "runtime" (except SetFinalizer):
  169. // it has few interesting effects on aliasing
  170. // and is full of unsafe code we can't analyze.
  171. impl = ext۰NoEffect
  172. }
  173. a.intrinsics[fn] = impl
  174. }
  175. return impl
  176. }
  177. // isReflect reports whether fn belongs to the "reflect" package.
  178. func (a *analysis) isReflect(fn *ssa.Function) bool {
  179. if a.reflectValueObj == nil {
  180. return false // "reflect" package not loaded
  181. }
  182. reflectPackage := a.reflectValueObj.Pkg()
  183. if fn.Pkg != nil && fn.Pkg.Pkg == reflectPackage {
  184. return true
  185. }
  186. // Synthetic wrappers have a nil Pkg, so they slip through the
  187. // previous check. Check the receiver package.
  188. // TODO(adonovan): should synthetic wrappers have a non-nil Pkg?
  189. if recv := fn.Signature.Recv(); recv != nil {
  190. if named, ok := deref(recv.Type()).(*types.Named); ok {
  191. if named.Obj().Pkg() == reflectPackage {
  192. return true // e.g. wrapper of (reflect.Value).f
  193. }
  194. }
  195. }
  196. return false
  197. }
  198. // A trivial intrinsic suitable for any function that does not:
  199. // 1) induce aliases between its arguments or any global variables;
  200. // 2) call any functions; or
  201. // 3) create any labels.
  202. //
  203. // Many intrinsics (such as CompareAndSwapInt32) have a fourth kind of
  204. // effect: loading or storing through a pointer. Though these could
  205. // be significant, we deliberately ignore them because they are
  206. // generally not worth the effort.
  207. //
  208. // We sometimes violate condition #3 if the function creates only
  209. // non-function labels, as the control-flow graph is still sound.
  210. //
  211. func ext۰NoEffect(a *analysis, cgn *cgnode) {}
  212. func ext۰NotYetImplemented(a *analysis, cgn *cgnode) {
  213. fn := cgn.fn
  214. a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
  215. }
  216. // ---------- func runtime.SetFinalizer(x, f interface{}) ----------
  217. // runtime.SetFinalizer(x, f)
  218. type runtimeSetFinalizerConstraint struct {
  219. targets nodeid // (indirect)
  220. f nodeid // (ptr)
  221. x nodeid
  222. }
  223. func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f }
  224. func (c *runtimeSetFinalizerConstraint) presolve(h *hvn) {
  225. h.markIndirect(onodeid(c.targets), "SetFinalizer.targets")
  226. }
  227. func (c *runtimeSetFinalizerConstraint) renumber(mapping []nodeid) {
  228. c.targets = mapping[c.targets]
  229. c.f = mapping[c.f]
  230. c.x = mapping[c.x]
  231. }
  232. func (c *runtimeSetFinalizerConstraint) String() string {
  233. return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f)
  234. }
  235. func (c *runtimeSetFinalizerConstraint) solve(a *analysis, delta *nodeset) {
  236. for _, fObj := range delta.AppendTo(a.deltaSpace) {
  237. tDyn, f, indirect := a.taggedValue(nodeid(fObj))
  238. if indirect {
  239. // TODO(adonovan): we'll need to implement this
  240. // when we start creating indirect tagged objects.
  241. panic("indirect tagged object")
  242. }
  243. tSig, ok := tDyn.Underlying().(*types.Signature)
  244. if !ok {
  245. continue // not a function
  246. }
  247. if tSig.Recv() != nil {
  248. panic(tSig)
  249. }
  250. if tSig.Params().Len() != 1 {
  251. continue // not a unary function
  252. }
  253. // Extract x to tmp.
  254. tx := tSig.Params().At(0).Type()
  255. tmp := a.addNodes(tx, "SetFinalizer.tmp")
  256. a.typeAssert(tx, tmp, c.x, false)
  257. // Call f(tmp).
  258. a.store(f, tmp, 1, a.sizeof(tx))
  259. // Add dynamic call target.
  260. if a.onlineCopy(c.targets, f) {
  261. a.addWork(c.targets)
  262. }
  263. }
  264. }
  265. func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) {
  266. // This is the shared contour, used for dynamic calls.
  267. targets := a.addOneNode(tInvalid, "SetFinalizer.targets", nil)
  268. cgn.sites = append(cgn.sites, &callsite{targets: targets})
  269. params := a.funcParams(cgn.obj)
  270. a.addConstraint(&runtimeSetFinalizerConstraint{
  271. targets: targets,
  272. x: params,
  273. f: params + 1,
  274. })
  275. }
  276. // ---------- func time.startTimer(t *runtimeTimer) ----------
  277. // time.StartTimer(t)
  278. type timeStartTimerConstraint struct {
  279. targets nodeid // (indirect)
  280. t nodeid // (ptr)
  281. }
  282. func (c *timeStartTimerConstraint) ptr() nodeid { return c.t }
  283. func (c *timeStartTimerConstraint) presolve(h *hvn) {
  284. h.markIndirect(onodeid(c.targets), "StartTimer.targets")
  285. }
  286. func (c *timeStartTimerConstraint) renumber(mapping []nodeid) {
  287. c.targets = mapping[c.targets]
  288. c.t = mapping[c.t]
  289. }
  290. func (c *timeStartTimerConstraint) String() string {
  291. return fmt.Sprintf("time.startTimer(n%d)", c.t)
  292. }
  293. func (c *timeStartTimerConstraint) solve(a *analysis, delta *nodeset) {
  294. for _, tObj := range delta.AppendTo(a.deltaSpace) {
  295. t := nodeid(tObj)
  296. // We model startTimer as if it was defined thus:
  297. // func startTimer(t *runtimeTimer) { t.f(t.arg) }
  298. // We hard-code the field offsets of time.runtimeTimer:
  299. // type runtimeTimer struct {
  300. // 0 __identity__
  301. // 1 i int32
  302. // 2 when int64
  303. // 3 period int64
  304. // 4 f func(int64, interface{})
  305. // 5 arg interface{}
  306. // }
  307. f := t + 4
  308. arg := t + 5
  309. // store t.arg to t.f.params[0]
  310. // (offset 1 => skip identity)
  311. a.store(f, arg, 1, 1)
  312. // Add dynamic call target.
  313. if a.onlineCopy(c.targets, f) {
  314. a.addWork(c.targets)
  315. }
  316. }
  317. }
  318. func ext۰time۰startTimer(a *analysis, cgn *cgnode) {
  319. // This is the shared contour, used for dynamic calls.
  320. targets := a.addOneNode(tInvalid, "startTimer.targets", nil)
  321. cgn.sites = append(cgn.sites, &callsite{targets: targets})
  322. params := a.funcParams(cgn.obj)
  323. a.addConstraint(&timeStartTimerConstraint{
  324. targets: targets,
  325. t: params,
  326. })
  327. }