summaryrefslogtreecommitdiffstats
path: root/misc/cgo/testsanitizers/testdata
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
commit73df946d56c74384511a194dd01dbe099584fd1a (patch)
treefd0bcea490dd81327ddfbb31e215439672c9a068 /misc/cgo/testsanitizers/testdata
parentInitial commit. (diff)
downloadgolang-1.16-upstream.tar.xz
golang-1.16-upstream.zip
Adding upstream version 1.16.10.upstream/1.16.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'misc/cgo/testsanitizers/testdata')
-rw-r--r--misc/cgo/testsanitizers/testdata/msan.go35
-rw-r--r--misc/cgo/testsanitizers/testdata/msan2.go35
-rw-r--r--misc/cgo/testsanitizers/testdata/msan2_cmsan.go38
-rw-r--r--misc/cgo/testsanitizers/testdata/msan3.go33
-rw-r--r--misc/cgo/testsanitizers/testdata/msan4.go50
-rw-r--r--misc/cgo/testsanitizers/testdata/msan5.go57
-rw-r--r--misc/cgo/testsanitizers/testdata/msan6.go72
-rw-r--r--misc/cgo/testsanitizers/testdata/msan7.go38
-rw-r--r--misc/cgo/testsanitizers/testdata/msan_fail.go36
-rw-r--r--misc/cgo/testsanitizers/testdata/msan_shared.go12
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan.go44
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan10.go31
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan11.go55
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan12.go35
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan2.go55
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan3.go40
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan4.go34
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan5.go51
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan6.go49
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan7.go40
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan8.go60
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan9.go67
-rw-r--r--misc/cgo/testsanitizers/testdata/tsan_shared.go63
23 files changed, 1030 insertions, 0 deletions
diff --git a/misc/cgo/testsanitizers/testdata/msan.go b/misc/cgo/testsanitizers/testdata/msan.go
new file mode 100644
index 0000000..7915fa8
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan2.go b/misc/cgo/testsanitizers/testdata/msan2.go
new file mode 100644
index 0000000..6690cb0
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan2_cmsan.go b/misc/cgo/testsanitizers/testdata/msan2_cmsan.go
new file mode 100644
index 0000000..8fdaea9
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/msan2_cmsan.go
@@ -0,0 +1,38 @@
+// 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
+
+/*
+#cgo LDFLAGS: -fsanitize=memory
+#cgo CPPFLAGS: -fsanitize=memory
+
+#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/misc/cgo/testsanitizers/testdata/msan3.go b/misc/cgo/testsanitizers/testdata/msan3.go
new file mode 100644
index 0000000..61a9c29
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan4.go b/misc/cgo/testsanitizers/testdata/msan4.go
new file mode 100644
index 0000000..6c91ff5
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan5.go b/misc/cgo/testsanitizers/testdata/msan5.go
new file mode 100644
index 0000000..f1479eb
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan6.go b/misc/cgo/testsanitizers/testdata/msan6.go
new file mode 100644
index 0000000..003989c
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/msan6.go
@@ -0,0 +1,72 @@
+// Copyright 2018 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
+
+// A C function returning a value on the Go stack could leave the Go
+// stack marked as uninitialized, potentially causing a later error
+// when the stack is used for something else. Issue 26209.
+
+/*
+#cgo LDFLAGS: -fsanitize=memory
+#cgo CPPFLAGS: -fsanitize=memory
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ uintptr_t a[20];
+} S;
+
+S f() {
+ S *p;
+
+ p = (S *)(malloc(sizeof(S)));
+ p->a[0] = 0;
+ return *p;
+}
+*/
+import "C"
+
+// allocateStack extends the stack so that stack copying doesn't
+// confuse the msan data structures.
+//go:noinline
+func allocateStack(i int) int {
+ if i == 0 {
+ return i
+ }
+ return allocateStack(i - 1)
+}
+
+// F1 marks a chunk of stack as uninitialized.
+// C.f returns an uninitialized struct on the stack, so msan will mark
+// the stack as uninitialized.
+//go:noinline
+func F1() uintptr {
+ s := C.f()
+ return uintptr(s.a[0])
+}
+
+// F2 allocates a struct on the stack and converts it to an empty interface,
+// which will call msanread and see that the data appears uninitialized.
+//go:noinline
+func F2() interface{} {
+ return C.S{}
+}
+
+func poisonStack(i int) int {
+ if i == 0 {
+ return int(F1())
+ }
+ F1()
+ r := poisonStack(i - 1)
+ F2()
+ return r
+}
+
+func main() {
+ allocateStack(16384)
+ poisonStack(128)
+}
diff --git a/misc/cgo/testsanitizers/testdata/msan7.go b/misc/cgo/testsanitizers/testdata/msan7.go
new file mode 100644
index 0000000..2f29fd2
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/msan7.go
@@ -0,0 +1,38 @@
+// Copyright 2020 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
+
+// Test passing C struct to exported Go function.
+
+/*
+#include <stdint.h>
+#include <stdlib.h>
+
+// T is a C struct with alignment padding after b.
+// The padding bytes are not considered initialized by MSAN.
+// It is big enough to be passed on stack in C ABI (and least
+// on AMD64).
+typedef struct { char b; uintptr_t x, y; } T;
+
+extern void F(T);
+
+// Use weak as a hack to permit defining a function even though we use export.
+void CF(int x) __attribute__ ((weak));
+void CF(int x) {
+ T *t = malloc(sizeof(T));
+ t->b = (char)x;
+ t->x = x;
+ t->y = x;
+ F(*t);
+}
+*/
+import "C"
+
+//export F
+func F(t C.T) { println(t.b, t.x, t.y) }
+
+func main() {
+ C.CF(C.int(0))
+}
diff --git a/misc/cgo/testsanitizers/testdata/msan_fail.go b/misc/cgo/testsanitizers/testdata/msan_fail.go
new file mode 100644
index 0000000..4c8dab3
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/msan_shared.go b/misc/cgo/testsanitizers/testdata/msan_shared.go
new file mode 100644
index 0000000..966947c
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan.go b/misc/cgo/testsanitizers/testdata/tsan.go
new file mode 100644
index 0000000..6c377a7
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan10.go b/misc/cgo/testsanitizers/testdata/tsan10.go
new file mode 100644
index 0000000..a40f245
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/tsan10.go
@@ -0,0 +1,31 @@
+// 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.
+
+package main
+
+// This program hung when run under the C/C++ ThreadSanitizer.
+// TSAN defers asynchronous signals until the signaled thread calls into libc.
+// Since the Go runtime makes direct futex syscalls, Go runtime threads could
+// run for an arbitrarily long time without triggering the libc interceptors.
+// See https://golang.org/issue/18717.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+*/
+import "C"
+
+func main() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, syscall.SIGUSR1)
+ defer signal.Stop(c)
+ syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+ <-c
+}
diff --git a/misc/cgo/testsanitizers/testdata/tsan11.go b/misc/cgo/testsanitizers/testdata/tsan11.go
new file mode 100644
index 0000000..70ac9c8
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/tsan11.go
@@ -0,0 +1,55 @@
+// 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.
+
+package main
+
+// This program hung when run under the C/C++ ThreadSanitizer. TSAN defers
+// asynchronous signals until the signaled thread calls into libc. The runtime's
+// sysmon goroutine idles itself using direct usleep syscalls, so it could
+// run for an arbitrarily long time without triggering the libc interceptors.
+// See https://golang.org/issue/18717.
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+/*
+#cgo CFLAGS: -g -fsanitize=thread
+#cgo LDFLAGS: -g -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void raise_usr2(int signo) {
+ raise(SIGUSR2);
+}
+
+static void register_handler(int signo) {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_ONSTACK;
+ sa.sa_handler = raise_usr2;
+
+ if (sigaction(SIGUSR1, &sa, NULL) != 0) {
+ perror("failed to register SIGUSR1 handler");
+ exit(EXIT_FAILURE);
+ }
+}
+*/
+import "C"
+
+func main() {
+ ch := make(chan os.Signal)
+ signal.Notify(ch, syscall.SIGUSR2)
+
+ C.register_handler(C.int(syscall.SIGUSR1))
+ syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+
+ <-ch
+}
diff --git a/misc/cgo/testsanitizers/testdata/tsan12.go b/misc/cgo/testsanitizers/testdata/tsan12.go
new file mode 100644
index 0000000..3e767ee
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/tsan12.go
@@ -0,0 +1,35 @@
+// 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.
+
+package main
+
+// This program hung when run under the C/C++ ThreadSanitizer. TSAN installs a
+// libc interceptor that writes signal handlers to a global variable within the
+// TSAN runtime instead of making a sigaction system call. A bug in
+// syscall.runtime_AfterForkInChild corrupted TSAN's signal forwarding table
+// during calls to (*os/exec.Cmd).Run, causing the parent process to fail to
+// invoke signal handlers.
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "os/signal"
+ "syscall"
+)
+
+import "C"
+
+func main() {
+ ch := make(chan os.Signal)
+ signal.Notify(ch, syscall.SIGUSR1)
+
+ if err := exec.Command("true").Run(); err != nil {
+ fmt.Fprintf(os.Stderr, "Unexpected error from `true`: %v", err)
+ os.Exit(1)
+ }
+
+ syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
+ <-ch
+}
diff --git a/misc/cgo/testsanitizers/testdata/tsan2.go b/misc/cgo/testsanitizers/testdata/tsan2.go
new file mode 100644
index 0000000..5018a19
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan3.go b/misc/cgo/testsanitizers/testdata/tsan3.go
new file mode 100644
index 0000000..87f6c80
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan4.go b/misc/cgo/testsanitizers/testdata/tsan4.go
new file mode 100644
index 0000000..f0c76d8
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan5.go b/misc/cgo/testsanitizers/testdata/tsan5.go
new file mode 100644
index 0000000..1214a77
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan6.go b/misc/cgo/testsanitizers/testdata/tsan6.go
new file mode 100644
index 0000000..c96f08d
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan7.go b/misc/cgo/testsanitizers/testdata/tsan7.go
new file mode 100644
index 0000000..2fb9e45
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan8.go b/misc/cgo/testsanitizers/testdata/tsan8.go
new file mode 100644
index 0000000..88d82a6
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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/misc/cgo/testsanitizers/testdata/tsan9.go b/misc/cgo/testsanitizers/testdata/tsan9.go
new file mode 100644
index 0000000..f166d8b
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/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()
+}
diff --git a/misc/cgo/testsanitizers/testdata/tsan_shared.go b/misc/cgo/testsanitizers/testdata/tsan_shared.go
new file mode 100644
index 0000000..55ff67e
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/tsan_shared.go
@@ -0,0 +1,63 @@
+// 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.
+
+package main
+
+// This program failed with SIGSEGV when run under the C/C++ ThreadSanitizer.
+// The Go runtime had re-registered the C handler with the wrong flags due to a
+// typo, resulting in null pointers being passed for the info and context
+// parameters to the handler.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+
+void check_params(int signo, siginfo_t *info, void *context) {
+ ucontext_t* uc = (ucontext_t*)(context);
+
+ if (info->si_signo != signo) {
+ fprintf(stderr, "info->si_signo does not match signo.\n");
+ abort();
+ }
+
+ if (uc->uc_stack.ss_size == 0) {
+ fprintf(stderr, "uc_stack has size 0.\n");
+ abort();
+ }
+}
+
+
+// Set up the signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void register_handler(void) __attribute__ ((constructor (200)));
+
+static void register_handler() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = check_params;
+
+ if (sigaction(SIGUSR1, &sa, NULL) != 0) {
+ perror("failed to register SIGUSR1 handler");
+ exit(EXIT_FAILURE);
+ }
+}
+*/
+import "C"
+
+import "syscall"
+
+func init() {
+ C.raise(C.int(syscall.SIGUSR1))
+}
+
+func main() {}