diff options
author | Matthew Dempsky <mdempsky@google.com> | 2019-02-12 19:40:42 -0800 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2019-10-17 00:40:21 +0000 |
commit | 80a6fedea05dbdab2e55b2ba922faeaf4155a981 (patch) | |
tree | 2bf6dc699a1f356e4a3ac0320e521d61ae631539 /src/runtime/checkptr.go | |
parent | 3b003c3edb013786caeea6c0913b2e21fc4ad66b (diff) | |
download | go-80a6fedea05dbdab2e55b2ba922faeaf4155a981.tar.gz go-80a6fedea05dbdab2e55b2ba922faeaf4155a981.zip |
cmd/compile: add -d=checkptr to validate unsafe.Pointer rules
This CL adds -d=checkptr as a compile-time option for adding
instrumentation to check that Go code is following unsafe.Pointer
safety rules dynamically. In particular, it currently checks two
things:
1. When converting unsafe.Pointer to *T, make sure the resulting
pointer is aligned appropriately for T.
2. When performing pointer arithmetic, if the result points to a Go
heap object, make sure we can find an unsafe.Pointer-typed operand
that pointed into the same object.
These checks are currently disabled for the runtime, and can also be
disabled through a new //go:nocheckptr annotation. The latter is
necessary for functions like strings.noescape, which intentionally
violate safety rules to workaround escape analysis limitations.
Fixes #22218.
Change-Id: If5a51273881d93048f74bcff10a3275c9c91da6a
Reviewed-on: https://go-review.googlesource.com/c/go/+/162237
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/runtime/checkptr.go')
-rw-r--r-- | src/runtime/checkptr.go | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/src/runtime/checkptr.go b/src/runtime/checkptr.go new file mode 100644 index 0000000000..040a19a39c --- /dev/null +++ b/src/runtime/checkptr.go @@ -0,0 +1,50 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "unsafe" + +type ptrAlign struct { + ptr unsafe.Pointer + align uintptr +} + +func checkptrAlignment(p unsafe.Pointer, elem *_type) { + // TODO(mdempsky): What about fieldAlign? + if uintptr(p)&(uintptr(elem.align)-1) != 0 { + panic(ptrAlign{p, uintptr(elem.align)}) + } +} + +type ptrArith struct { + ptr unsafe.Pointer + originals []unsafe.Pointer +} + +func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) { + if 0 < uintptr(p) && uintptr(p) < minLegalPointer { + panic(ptrArith{p, originals}) + } + + base := checkptrBase(p) + if base == 0 { + return + } + + for _, original := range originals { + if base == checkptrBase(original) { + return + } + } + + panic(ptrArith{p, originals}) +} + +func checkptrBase(p unsafe.Pointer) uintptr { + base, _, _ := findObject(uintptr(p), 0, 0) + // TODO(mdempsky): If base == 0, then check if p points to the + // stack or a global variable. + return base +} |