mirror of
https://github.com/golang/go
synced 2024-11-22 15:44:53 -07:00
cmd/compile: set conversions to unsafe.Pointer as an escaping operation when -asan is enabled
When ASan is enabled, treat conversions to unsafe.Pointer as an escaping operation. In this way, all pointer operations on the stack objects will become operations on the escaped heap objects. As we've already supported ASan detection of error memory accesses to heap objects. With this trick, we can use -asan option to report errors on bad stack operations. Add test cases. Updates #44853. CustomizedGitHooks: yes Change-Id: I4e7fe46a3ce01f0d219e6a67dc50f4aff7d2ad87 Reviewed-on: https://go-review.googlesource.com/c/go/+/325629 Trust: Fannie Zhang <Fannie.Zhang@arm.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
d34287a4f6
commit
5fd0ed7aaf
@ -41,6 +41,9 @@ func TestASAN(t *testing.T) {
|
||||
{src: "asan4_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan4_fail.go:13"},
|
||||
{src: "asan5_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan5_fail.go:18"},
|
||||
{src: "asan_useAfterReturn.go"},
|
||||
{src: "asan_unsafe_fail1.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail1.go:25"},
|
||||
{src: "asan_unsafe_fail2.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail2.go:25"},
|
||||
{src: "asan_unsafe_fail3.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail3.go:18"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
|
27
misc/cgo/testsanitizers/testdata/asan_unsafe_fail1.go
vendored
Normal file
27
misc/cgo/testsanitizers/testdata/asan_unsafe_fail1.go
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 1
|
||||
b := 2
|
||||
c := add(a, b)
|
||||
d := a + b
|
||||
fmt.Println(c, d)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func add(a1, b1 int) int {
|
||||
// The arguments.
|
||||
// When -asan is enabled, unsafe.Pointer(&a1) conversion is escaping.
|
||||
var p *int = (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&a1)) + 1*unsafe.Sizeof(int(1))))
|
||||
*p = 10 // BOOM
|
||||
return a1 + b1
|
||||
}
|
28
misc/cgo/testsanitizers/testdata/asan_unsafe_fail2.go
vendored
Normal file
28
misc/cgo/testsanitizers/testdata/asan_unsafe_fail2.go
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 1
|
||||
b := 2
|
||||
c := add(a, b)
|
||||
d := a + b
|
||||
fmt.Println(c, d)
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func add(a1, b1 int) (ret int) {
|
||||
// The return value
|
||||
// When -asan is enabled, the unsafe.Pointer(&ret) conversion is escaping.
|
||||
var p *int = (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&ret)) + 1*unsafe.Sizeof(int(1))))
|
||||
*p = 123 // BOOM
|
||||
ret = a1 + b1
|
||||
return
|
||||
}
|
21
misc/cgo/testsanitizers/testdata/asan_unsafe_fail3.go
vendored
Normal file
21
misc/cgo/testsanitizers/testdata/asan_unsafe_fail3.go
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2022 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 main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := 1
|
||||
b := 2
|
||||
// The local variables.
|
||||
// When -asan is enabled, the unsafe.Pointer(&a) conversion is escaping.
|
||||
var p *int = (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&a)) + 1*unsafe.Sizeof(int(1))))
|
||||
*p = 20 // BOOM
|
||||
d := a + b
|
||||
fmt.Println(d)
|
||||
}
|
@ -100,9 +100,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
||||
|
||||
case ir.OCONV, ir.OCONVNOP:
|
||||
n := n.(*ir.ConvExpr)
|
||||
if ir.ShouldCheckPtr(e.curfn, 2) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() {
|
||||
// When -d=checkptr=2 is enabled, treat
|
||||
// conversions to unsafe.Pointer as an
|
||||
if (ir.ShouldCheckPtr(e.curfn, 2) || ir.ShouldAsanCheckPtr(e.curfn)) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() {
|
||||
// When -d=checkptr=2 or -asan is enabled,
|
||||
// treat conversions to unsafe.Pointer as an
|
||||
// escaping operation. This allows better
|
||||
// runtime instrumentation, since we can more
|
||||
// easily detect object boundaries on the heap
|
||||
|
@ -1035,6 +1035,12 @@ func ShouldCheckPtr(fn *Func, level int) bool {
|
||||
return base.Debug.Checkptr >= level && fn.Pragma&NoCheckPtr == 0
|
||||
}
|
||||
|
||||
// ShouldAsanCheckPtr reports whether pointer checking should be enabled for
|
||||
// function fn when -asan is enabled.
|
||||
func ShouldAsanCheckPtr(fn *Func) bool {
|
||||
return base.Flag.ASan && fn.Pragma&NoCheckPtr == 0
|
||||
}
|
||||
|
||||
// IsReflectHeaderDataField reports whether l is an expression p.Data
|
||||
// where p has type reflect.SliceHeader or reflect.StringHeader.
|
||||
func IsReflectHeaderDataField(l Node) bool {
|
||||
|
Loading…
Reference in New Issue
Block a user