summaryrefslogtreecommitdiff
path: root/libgo/misc/cgo/testsanitizers
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/misc/cgo/testsanitizers')
-rw-r--r--libgo/misc/cgo/testsanitizers/msan.go35
-rw-r--r--libgo/misc/cgo/testsanitizers/msan2.go35
-rw-r--r--libgo/misc/cgo/testsanitizers/msan3.go33
-rw-r--r--libgo/misc/cgo/testsanitizers/msan4.go50
-rw-r--r--libgo/misc/cgo/testsanitizers/msan5.go57
-rw-r--r--libgo/misc/cgo/testsanitizers/msan_fail.go36
-rw-r--r--libgo/misc/cgo/testsanitizers/msan_shared.go12
-rw-r--r--libgo/misc/cgo/testsanitizers/test.bash204
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan.go44
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan2.go55
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan3.go40
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan4.go34
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan5.go51
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan6.go49
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan7.go40
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan8.go60
-rw-r--r--libgo/misc/cgo/testsanitizers/tsan9.go67
17 files changed, 902 insertions, 0 deletions
diff --git a/libgo/misc/cgo/testsanitizers/msan.go b/libgo/misc/cgo/testsanitizers/msan.go
new file mode 100644
index 00000000000..7915fa84f60
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan.go
@@ -0,0 +1,35 @@
+// Copyright 2015 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 <stdint.h>
+
+void f(int32_t *p, int n) {
+ int i;
+
+ for (i = 0; i < n; i++) {
+ p[i] = (int32_t)i;
+ }
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "unsafe"
+)
+
+func main() {
+ a := make([]int32, 10)
+ C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+ for i, v := range a {
+ if i != int(v) {
+ fmt.Println("bad %d: %v\n", i, a)
+ os.Exit(1)
+ }
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan2.go b/libgo/misc/cgo/testsanitizers/msan2.go
new file mode 100644
index 00000000000..6690cb034fc
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan2.go
@@ -0,0 +1,35 @@
+// Copyright 2015 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 <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+void f(int32_t *p, int n) {
+ int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n);
+ memcpy(p, q, n * sizeof(*p));
+ free(q);
+}
+
+void g(int32_t *p, int n) {
+ if (p[4] != 1) {
+ abort();
+ }
+}
+*/
+import "C"
+
+import (
+ "unsafe"
+)
+
+func main() {
+ a := make([]int32, 10)
+ C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+ a[4] = 1
+ C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan3.go b/libgo/misc/cgo/testsanitizers/msan3.go
new file mode 100644
index 00000000000..61a9c29e1a9
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan3.go
@@ -0,0 +1,33 @@
+// Copyright 2015 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
+
+/*
+extern int *GoFn(int *);
+
+// Yes, you can have definitions if you use //export, as long as they are weak.
+int f(void) __attribute__ ((weak));
+
+int f() {
+ int i;
+ int *p = GoFn(&i);
+ if (*p != 12345)
+ return 0;
+ return 1;
+}
+*/
+import "C"
+
+//export GoFn
+func GoFn(p *C.int) *C.int {
+ *p = C.int(12345)
+ return p
+}
+
+func main() {
+ if r := C.f(); r != 1 {
+ panic(r)
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan4.go b/libgo/misc/cgo/testsanitizers/msan4.go
new file mode 100644
index 00000000000..6c91ff5f091
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan4.go
@@ -0,0 +1,50 @@
+// Copyright 2015 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 memory profiler can call copy from a slice on the system stack,
+// which msan used to think meant a reference to uninitialized memory.
+
+/*
+#include <time.h>
+#include <unistd.h>
+
+extern void Nop(char*);
+
+// Use weak as a hack to permit defining a function even though we use export.
+void poison() __attribute__ ((weak));
+
+// Poison the stack.
+void poison() {
+ char a[1024];
+ Nop(&a[0]);
+}
+
+*/
+import "C"
+
+import (
+ "runtime"
+)
+
+func main() {
+ runtime.MemProfileRate = 1
+ start(100)
+}
+
+func start(i int) {
+ if i == 0 {
+ return
+ }
+ C.poison()
+ // Tie up a thread.
+ // We won't actually wait for this sleep to complete.
+ go func() { C.sleep(1) }()
+ start(i - 1)
+}
+
+//export Nop
+func Nop(*C.char) {
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan5.go b/libgo/misc/cgo/testsanitizers/msan5.go
new file mode 100644
index 00000000000..f1479eb8a00
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan5.go
@@ -0,0 +1,57 @@
+// Copyright 2016 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
+
+// Using reflect to set a value was not seen by msan.
+
+/*
+#include <stdlib.h>
+
+extern void Go1(int*);
+extern void Go2(char*);
+
+// Use weak as a hack to permit defining a function even though we use export.
+void C1() __attribute__ ((weak));
+void C2() __attribute__ ((weak));
+
+void C1() {
+ int i;
+ Go1(&i);
+ if (i != 42) {
+ abort();
+ }
+}
+
+void C2() {
+ char a[2];
+ a[1] = 42;
+ Go2(a);
+ if (a[0] != 42) {
+ abort();
+ }
+}
+*/
+import "C"
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+//export Go1
+func Go1(p *C.int) {
+ reflect.ValueOf(p).Elem().Set(reflect.ValueOf(C.int(42)))
+}
+
+//export Go2
+func Go2(p *C.char) {
+ a := (*[2]byte)(unsafe.Pointer(p))
+ reflect.Copy(reflect.ValueOf(a[:1]), reflect.ValueOf(a[1:]))
+}
+
+func main() {
+ C.C1()
+ C.C2()
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan_fail.go b/libgo/misc/cgo/testsanitizers/msan_fail.go
new file mode 100644
index 00000000000..4c8dab34f6e
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan_fail.go
@@ -0,0 +1,36 @@
+// Copyright 2015 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 <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+void f(int32_t *p, int n) {
+ int32_t * volatile q = (int32_t *)malloc(sizeof(int32_t) * n);
+ memcpy(p, q, n * sizeof(*p));
+ free(q);
+}
+
+void g(int32_t *p, int n) {
+ if (p[4] != 1) {
+ // We shouldn't get here; msan should stop us first.
+ exit(0);
+ }
+}
+*/
+import "C"
+
+import (
+ "unsafe"
+)
+
+func main() {
+ a := make([]int32, 10)
+ C.f((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+ a[3] = 1
+ C.g((*C.int32_t)(unsafe.Pointer(&a[0])), C.int(len(a)))
+}
diff --git a/libgo/misc/cgo/testsanitizers/msan_shared.go b/libgo/misc/cgo/testsanitizers/msan_shared.go
new file mode 100644
index 00000000000..966947cac35
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/msan_shared.go
@@ -0,0 +1,12 @@
+// Copyright 2017 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.
+
+// This program segfaulted during libpreinit when built with -msan:
+// http://golang.org/issue/18707
+
+package main
+
+import "C"
+
+func main() {}
diff --git a/libgo/misc/cgo/testsanitizers/test.bash b/libgo/misc/cgo/testsanitizers/test.bash
new file mode 100644
index 00000000000..4da85020d89
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/test.bash
@@ -0,0 +1,204 @@
+#!/usr/bin/env bash
+# Copyright 2015 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.
+
+# This directory is intended to test the use of Go with sanitizers
+# like msan, asan, etc. See https://github.com/google/sanitizers .
+
+set -e
+
+# The sanitizers were originally developed with clang, so prefer it.
+CC=cc
+if test -x "$(type -p clang)"; then
+ CC=clang
+fi
+export CC
+
+if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then
+ echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2
+ exit 0
+fi
+
+msan=yes
+
+TMPDIR=${TMPDIR:-/tmp}
+echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
+if $CC -fsanitize=memory -o ${TMPDIR}/testsanitizers$$ ${TMPDIR}/testsanitizers$$.c 2>&1 | grep "unrecognized" >& /dev/null; then
+ echo "skipping msan tests: $CC -fsanitize=memory not supported"
+ msan=no
+elif ! test -x ${TMPDIR}/testsanitizers$$; then
+ echo "skipping msan tests: $CC -fsanitize-memory did not generate an executable"
+ msan=no
+elif ! ${TMPDIR}/testsanitizers$$ >/dev/null 2>&1; then
+ echo "skipping msan tests: $CC -fsanitize-memory generates broken executable"
+ msan=no
+fi
+rm -f ${TMPDIR}/testsanitizers$$.*
+
+tsan=yes
+
+# The memory and thread sanitizers in versions of clang before 3.6
+# don't work with Go.
+if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then
+ ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
+ major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
+ minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
+ if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
+ echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)"
+ msan=no
+ tsan=no
+ fi
+
+ # Clang before 3.8 does not work with Linux at or after 4.1.
+ # golang.org/issue/12898.
+ if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
+ if test "$(uname)" = Linux; then
+ linuxver=$(uname -r)
+ linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/')
+ linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
+ if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then
+ echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
+ msan=no
+ tsan=no
+ fi
+ fi
+ fi
+fi
+
+status=0
+
+testmsanshared() {
+ goos=$(go env GOOS)
+ suffix="-installsuffix testsanitizers"
+ libext="so"
+ if [ "$goos" == "darwin" ]; then
+ libext="dylib"
+ fi
+ go build -msan -buildmode=c-shared $suffix -o ${TMPDIR}/libmsanshared.$libext msan_shared.go
+
+ echo 'int main() { return 0; }' > ${TMPDIR}/testmsanshared.c
+ $CC $(go env GOGCCFLAGS) -fsanitize=memory -o ${TMPDIR}/testmsanshared ${TMPDIR}/testmsanshared.c ${TMPDIR}/libmsanshared.$libext
+
+ if ! LD_LIBRARY_PATH=. ${TMPDIR}/testmsanshared; then
+ echo "FAIL: msan_shared"
+ status=1
+ fi
+ rm -f ${TMPDIR}/{testmsanshared,testmsanshared.c,libmsanshared.$libext}
+}
+
+if test "$msan" = "yes"; then
+ if ! go build -msan std; then
+ echo "FAIL: build -msan std"
+ status=1
+ fi
+
+ if ! go run -msan msan.go; then
+ echo "FAIL: msan"
+ status=1
+ fi
+
+ if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
+ echo "FAIL: msan2 with -fsanitize=memory"
+ status=1
+ fi
+
+ if ! go run -msan -a msan2.go; then
+ echo "FAIL: msan2"
+ status=1
+ fi
+
+ if ! go run -msan msan3.go; then
+ echo "FAIL: msan3"
+ status=1
+ fi
+
+ if ! go run -msan msan4.go; then
+ echo "FAIL: msan4"
+ status=1
+ fi
+
+ if ! go run -msan msan5.go; then
+ echo "FAIL: msan5"
+ status=1
+ fi
+
+ if go run -msan msan_fail.go 2>/dev/null; then
+ echo "FAIL: msan_fail"
+ status=1
+ fi
+
+ testmsanshared
+fi
+
+if test "$tsan" = "yes"; then
+ echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
+ ok=yes
+ if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
+ ok=no
+ fi
+ if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
+ echo "skipping tsan tests: -fsanitize=thread not supported"
+ tsan=no
+ elif test "$ok" != "yes"; then
+ cat ${TMPDIR}/testsanitizers$$.err
+ echo "skipping tsan tests: -fsanitizer=thread build failed"
+ tsan=no
+ fi
+ rm -f ${TMPDIR}/testsanitizers$$*
+fi
+
+# Run a TSAN test.
+# $1 test name
+# $2 environment variables
+# $3 go run args
+testtsan() {
+ err=${TMPDIR}/tsanerr$$.out
+ if ! env $2 go run $3 $1 2>$err; then
+ cat $err
+ echo "FAIL: $1"
+ status=1
+ elif grep -i warning $err >/dev/null 2>&1; then
+ cat $err
+ echo "FAIL: $1"
+ status=1
+ fi
+ rm -f $err
+}
+
+if test "$tsan" = "yes"; then
+ testtsan tsan.go
+ testtsan tsan2.go
+ testtsan tsan3.go
+ testtsan tsan4.go
+ testtsan tsan8.go
+ testtsan tsan9.go
+
+ # These tests are only reliable using clang or GCC version 7 or later.
+ # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
+ ok=false
+ if ${CC} --version | grep clang >/dev/null 2>&1; then
+ ok=true
+ else
+ ver=$($CC -dumpversion)
+ major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
+ if test "$major" -lt 7; then
+ echo "skipping remaining TSAN tests: GCC version $major (older than 7)"
+ else
+ ok=true
+ fi
+ fi
+
+ if test "$ok" = "true"; then
+ # This test requires rebuilding os/user with -fsanitize=thread.
+ testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+
+ # This test requires rebuilding runtime/cgo with -fsanitize=thread.
+ testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+
+ # This test requires rebuilding runtime/cgo with -fsanitize=thread.
+ testtsan tsan7.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+ fi
+fi
+
+exit $status
diff --git a/libgo/misc/cgo/testsanitizers/tsan.go b/libgo/misc/cgo/testsanitizers/tsan.go
new file mode 100644
index 00000000000..6c377a701fb
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan.go
@@ -0,0 +1,44 @@
+// Copyright 2015 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
+
+// This program produced false race reports when run under the C/C++
+// ThreadSanitizer, as it did not understand the synchronization in
+// the Go code.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+int val;
+
+int getVal() {
+ return val;
+}
+
+void setVal(int i) {
+ val = i;
+}
+*/
+import "C"
+
+import (
+ "runtime"
+)
+
+func main() {
+ runtime.LockOSThread()
+ C.setVal(1)
+ c := make(chan bool)
+ go func() {
+ runtime.LockOSThread()
+ C.setVal(2)
+ c <- true
+ }()
+ <-c
+ if v := C.getVal(); v != 2 {
+ panic(v)
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan2.go b/libgo/misc/cgo/testsanitizers/tsan2.go
new file mode 100644
index 00000000000..5018a1987ca
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan2.go
@@ -0,0 +1,55 @@
+// Copyright 2015 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
+
+// This program produced false race reports when run under the C/C++
+// ThreadSanitizer, as it did not understand the synchronization in
+// the Go code.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+extern void GoRun(void);
+
+// Yes, you can have definitions if you use //export, as long as they are weak.
+
+int val __attribute__ ((weak));
+
+int run(void) __attribute__ ((weak));
+
+int run() {
+ val = 1;
+ GoRun();
+ return val;
+}
+
+void setVal(int) __attribute__ ((weak));
+
+void setVal(int i) {
+ val = i;
+}
+*/
+import "C"
+
+import "runtime"
+
+//export GoRun
+func GoRun() {
+ runtime.LockOSThread()
+ c := make(chan bool)
+ go func() {
+ runtime.LockOSThread()
+ C.setVal(2)
+ c <- true
+ }()
+ <-c
+}
+
+func main() {
+ if v := C.run(); v != 2 {
+ panic(v)
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan3.go b/libgo/misc/cgo/testsanitizers/tsan3.go
new file mode 100644
index 00000000000..87f6c80f1b1
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan3.go
@@ -0,0 +1,40 @@
+// Copyright 2016 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 stubs for the C functions read and write the same slot on the
+// g0 stack when copying arguments in and out.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+int Func1() {
+ return 0;
+}
+
+void Func2(int x) {
+ (void)x;
+}
+*/
+import "C"
+
+func main() {
+ const N = 10000
+ done := make(chan bool, N)
+ for i := 0; i < N; i++ {
+ go func() {
+ C.Func1()
+ done <- true
+ }()
+ go func() {
+ C.Func2(0)
+ done <- true
+ }()
+ }
+ for i := 0; i < 2*N; i++ {
+ <-done
+ }
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan4.go b/libgo/misc/cgo/testsanitizers/tsan4.go
new file mode 100644
index 00000000000..f0c76d84116
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan4.go
@@ -0,0 +1,34 @@
+// Copyright 2016 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
+
+// Check that calls to C.malloc/C.free do not trigger TSAN false
+// positive reports.
+
+// #cgo CFLAGS: -fsanitize=thread
+// #cgo LDFLAGS: -fsanitize=thread
+// #include <stdlib.h>
+import "C"
+
+import (
+ "runtime"
+ "sync"
+)
+
+func main() {
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ p := C.malloc(C.size_t(i * 10))
+ runtime.Gosched()
+ C.free(p)
+ }
+ }()
+ }
+ wg.Wait()
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan5.go b/libgo/misc/cgo/testsanitizers/tsan5.go
new file mode 100644
index 00000000000..1214a7743b6
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan5.go
@@ -0,0 +1,51 @@
+// Copyright 2016 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
+
+// Check that calls to C.malloc/C.free do not collide with the calls
+// made by the os/user package.
+
+// #cgo CFLAGS: -fsanitize=thread
+// #cgo LDFLAGS: -fsanitize=thread
+// #include <stdlib.h>
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "os/user"
+ "runtime"
+ "sync"
+)
+
+func main() {
+ u, err := user.Current()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ // Let the test pass.
+ os.Exit(0)
+ }
+
+ var wg sync.WaitGroup
+ for i := 0; i < 20; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 1000; i++ {
+ user.Lookup(u.Username)
+ runtime.Gosched()
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 1000; i++ {
+ p := C.malloc(C.size_t(len(u.Username) + 1))
+ runtime.Gosched()
+ C.free(p)
+ }
+ }()
+ }
+ wg.Wait()
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan6.go b/libgo/misc/cgo/testsanitizers/tsan6.go
new file mode 100644
index 00000000000..c96f08d2f37
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan6.go
@@ -0,0 +1,49 @@
+// Copyright 2016 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
+
+// Check that writes to Go allocated memory, with Go synchronization,
+// do not look like a race.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+void f(char *p) {
+ *p = 1;
+}
+*/
+import "C"
+
+import (
+ "runtime"
+ "sync"
+)
+
+func main() {
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+ c := make(chan []C.char, 100)
+ for i := 0; i < 10; i++ {
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ c <- make([]C.char, 4096)
+ runtime.Gosched()
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ p := &(<-c)[0]
+ mu.Lock()
+ C.f(p)
+ mu.Unlock()
+ }
+ }()
+ }
+ wg.Wait()
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan7.go b/libgo/misc/cgo/testsanitizers/tsan7.go
new file mode 100644
index 00000000000..2fb9e45ee2d
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan7.go
@@ -0,0 +1,40 @@
+// Copyright 2016 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
+
+// Setting an environment variable in a cgo program changes the C
+// environment. Test that this does not confuse the race detector.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "sync"
+ "time"
+)
+
+func main() {
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+ f := func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ time.Sleep(time.Microsecond)
+ mu.Lock()
+ s := fmt.Sprint(i)
+ os.Setenv("TSAN_TEST"+s, s)
+ mu.Unlock()
+ }
+ }
+ wg.Add(2)
+ go f()
+ go f()
+ wg.Wait()
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan8.go b/libgo/misc/cgo/testsanitizers/tsan8.go
new file mode 100644
index 00000000000..88d82a60789
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan8.go
@@ -0,0 +1,60 @@
+// Copyright 2016 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
+
+// This program failed when run under the C/C++ ThreadSanitizer. The TSAN
+// sigaction function interceptor returned SIG_DFL instead of the Go runtime's
+// handler in registerSegvForwarder.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sigaction prev_sa;
+
+void forwardSignal(int signo, siginfo_t *info, void *context) {
+ // One of sa_sigaction and/or sa_handler
+ if ((prev_sa.sa_flags&SA_SIGINFO) != 0) {
+ prev_sa.sa_sigaction(signo, info, context);
+ return;
+ }
+ if (prev_sa.sa_handler != SIG_IGN && prev_sa.sa_handler != SIG_DFL) {
+ prev_sa.sa_handler(signo);
+ return;
+ }
+
+ fprintf(stderr, "No Go handler to forward to!\n");
+ abort();
+}
+
+void registerSegvFowarder() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ sa.sa_sigaction = forwardSignal;
+
+ if (sigaction(SIGSEGV, &sa, &prev_sa) != 0) {
+ perror("failed to register SEGV forwarder");
+ exit(EXIT_FAILURE);
+ }
+}
+*/
+import "C"
+
+func main() {
+ C.registerSegvFowarder()
+
+ defer func() {
+ recover()
+ }()
+ var nilp *int
+ *nilp = 42
+}
diff --git a/libgo/misc/cgo/testsanitizers/tsan9.go b/libgo/misc/cgo/testsanitizers/tsan9.go
new file mode 100644
index 00000000000..f166d8b495a
--- /dev/null
+++ b/libgo/misc/cgo/testsanitizers/tsan9.go
@@ -0,0 +1,67 @@
+// Copyright 2016 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
+
+// This program failed when run under the C/C++ ThreadSanitizer. The
+// TSAN library was not keeping track of whether signals should be
+// delivered on the alternate signal stack, and the Go signal handler
+// was not preserving callee-saved registers from C callers.
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+void spin() {
+ size_t n;
+ struct timeval tvstart, tvnow;
+ int diff;
+ void *prev = NULL, *cur;
+
+ gettimeofday(&tvstart, NULL);
+ for (n = 0; n < 1<<20; n++) {
+ cur = malloc(n);
+ free(prev);
+ prev = cur;
+
+ gettimeofday(&tvnow, NULL);
+ diff = (tvnow.tv_sec - tvstart.tv_sec) * 1000 * 1000 + (tvnow.tv_usec - tvstart.tv_usec);
+
+ // Profile frequency is 100Hz so we should definitely
+ // get a signal in 50 milliseconds.
+ if (diff > 50 * 1000) {
+ break;
+ }
+ }
+
+ free(prev);
+}
+*/
+import "C"
+
+import (
+ "io/ioutil"
+ "runtime/pprof"
+ "time"
+)
+
+func goSpin() {
+ start := time.Now()
+ for n := 0; n < 1<<20; n++ {
+ _ = make([]byte, n)
+ if time.Since(start) > 50*time.Millisecond {
+ break
+ }
+ }
+}
+
+func main() {
+ pprof.StartCPUProfile(ioutil.Discard)
+ go C.spin()
+ goSpin()
+ pprof.StopCPUProfile()
+}