-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Run-TryBot: fannie zhang <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
- Loading branch information
1 parent
c1ea339
commit 3ee426a
Showing
8 changed files
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters