mirror of
https://github.com/golang/go
synced 2024-11-26 04:58:00 -07:00
cmd/dist: add asan tests in misc/cgo/testsanitizers package
Add asan tests to check the use of Go with -asan option. Currenly, the address sanitizer in Go only checks for error memory access to heap objects. TODO: Enable check for error memory access to global objects. Updates #44853. Change-Id: I83579f229f117b5684a369fc8f365f4dea140648 Reviewed-on: https://go-review.googlesource.com/c/go/+/298615 Trust: fannie zhang <Fannie.Zhang@arm.com> Run-TryBot: fannie zhang <Fannie.Zhang@arm.com> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
c1ea3395a6
commit
3ee426aefa
66
misc/cgo/testsanitizers/asan_test.go
Normal file
66
misc/cgo/testsanitizers/asan_test.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2021 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 sanitizers_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestASAN(t *testing.T) {
|
||||
goos, err := goEnv("GOOS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
goarch, err := goEnv("GOARCH")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// The asan tests require support for the -asan option.
|
||||
if !aSanSupported(goos, goarch) {
|
||||
t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
requireOvercommit(t)
|
||||
config := configure("address")
|
||||
config.skipIfCSanitizerBroken(t)
|
||||
|
||||
mustRun(t, config.goCmd("build", "std"))
|
||||
|
||||
cases := []struct {
|
||||
src string
|
||||
memoryAccessError string
|
||||
}{
|
||||
{src: "asan1_fail.go", memoryAccessError: "heap-use-after-free"},
|
||||
{src: "asan2_fail.go", memoryAccessError: "heap-buffer-overflow"},
|
||||
{src: "asan3_fail.go", memoryAccessError: "use-after-poison"},
|
||||
{src: "asan4_fail.go", memoryAccessError: "use-after-poison"},
|
||||
{src: "asan_useAfterReturn.go"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
name := strings.TrimSuffix(tc.src, ".go")
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := newTempDir(t)
|
||||
defer dir.RemoveAll(t)
|
||||
|
||||
outPath := dir.Join(name)
|
||||
mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
|
||||
|
||||
cmd := hangProneCmd(outPath)
|
||||
if tc.memoryAccessError != "" {
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil && strings.Contains(string(out), tc.memoryAccessError) {
|
||||
return
|
||||
}
|
||||
t.Fatalf("%#q exited without expected memory access error\n%s; got failure\n%s", strings.Join(cmd.Args, " "), tc.memoryAccessError, out)
|
||||
}
|
||||
mustRun(t, cmd)
|
||||
})
|
||||
}
|
||||
}
|
@ -267,6 +267,9 @@ func configure(sanitizer string) *config {
|
||||
c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
|
||||
}
|
||||
|
||||
case "address":
|
||||
c.goFlags = append(c.goFlags, "-asan")
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
|
||||
}
|
||||
@ -450,3 +453,14 @@ func mSanSupported(goos, goarch string) bool {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// aSanSupported is a copy of the function cmd/internal/sys.ASanSupported,
|
||||
// because the internal pacakage can't be used here.
|
||||
func aSanSupported(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "linux":
|
||||
return goarch == "amd64" || goarch == "arm64"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
28
misc/cgo/testsanitizers/testdata/asan1_fail.go
vendored
Normal file
28
misc/cgo/testsanitizers/testdata/asan1_fail.go
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int *p;
|
||||
int* test() {
|
||||
p = (int *)malloc(2 * sizeof(int));
|
||||
free(p);
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// C passes Go an invalid pointer.
|
||||
a := C.test()
|
||||
// Use after free
|
||||
*a = 2
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
fmt.Println(*a)
|
||||
}
|
34
misc/cgo/testsanitizers/testdata/asan2_fail.go
vendored
Normal file
34
misc/cgo/testsanitizers/testdata/asan2_fail.go
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int *p;
|
||||
int* f() {
|
||||
int i;
|
||||
p = (int *)malloc(5*sizeof(int));
|
||||
for (i = 0; i < 5; i++) {
|
||||
p[i] = i+10;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := C.f()
|
||||
q5 := (*C.int)(unsafe.Add(unsafe.Pointer(a), 4*5))
|
||||
// Access to C pointer out of bounds.
|
||||
*q5 = 100
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
fmt.Printf("q5: %d, %x\n", *q5, q5)
|
||||
}
|
23
misc/cgo/testsanitizers/testdata/asan3_fail.go
vendored
Normal file
23
misc/cgo/testsanitizers/testdata/asan3_fail.go
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test(int *a) {
|
||||
// Access Go pointer out of bounds.
|
||||
int c = a[5]; // BOOM
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
printf("a[5]=%d\n", c);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
cIntSlice := []C.int{200, 201, 203, 203, 204}
|
||||
C.test(&cIntSlice[0])
|
||||
}
|
22
misc/cgo/testsanitizers/testdata/asan4_fail.go
vendored
Normal file
22
misc/cgo/testsanitizers/testdata/asan4_fail.go
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void test(int* a) {
|
||||
// Access Go pointer out of bounds.
|
||||
a[3] = 300; // BOOM
|
||||
// We shouldn't get here; asan should stop us first.
|
||||
printf("a[3]=%d\n", a[3]);
|
||||
}*/
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
var cIntArray [2]C.int
|
||||
C.test(&cIntArray[0]) // cIntArray is moved to heap.
|
||||
}
|
26
misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go
vendored
Normal file
26
misc/cgo/testsanitizers/testdata/asan_useAfterReturn.go
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2021 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
|
||||
|
||||
// The -fsanitize=address option of C compier can detect stack-use-after-return bugs.
|
||||
// In the following program, the local variable 'local' was moved to heap by the Go
|
||||
// compiler because foo() is returning the reference to 'local', and return stack of
|
||||
// foo() will be invalid. Thus for main() to use the reference to 'local', the 'local'
|
||||
// must be available even after foo() has finished. Therefore, Go has no such issue.
|
||||
|
||||
import "fmt"
|
||||
|
||||
var ptr *int
|
||||
|
||||
func main() {
|
||||
foo()
|
||||
fmt.Printf("ptr=%x, %v", *ptr, ptr)
|
||||
}
|
||||
|
||||
func foo() {
|
||||
var local int
|
||||
local = 1
|
||||
ptr = &local // local is moved to heap.
|
||||
}
|
@ -36,6 +36,7 @@ func MSanSupported(goos, goarch string) bool {
|
||||
|
||||
// ASanSupported reports whether goos/goarch supports the address
|
||||
// sanitizer option.
|
||||
// There is a copy of this function in misc/cgo/testsanitizers/cc_test.go.
|
||||
func ASanSupported(goos, goarch string) bool {
|
||||
switch goos {
|
||||
case "linux":
|
||||
|
Loading…
Reference in New Issue
Block a user