status=1
fi
+ # This test requires rebuilding os/user with -fsanitize=thread.
+ if ! CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go run -installsuffix=tsan tsan5.go 2>$err; then
+ cat $err
+ echo "FAIL: tsan5"
+ status=1
+ elif grep -i warning $err >/dev/null 2>&1; then
+ cat $err
+ echo "FAIL: tsan5"
+ status=1
+ fi
+
rm -f $err
fi
--- /dev/null
+// 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()
+}
#define _cgo_tsan_release()
`
+// This must match the TSAN code in runtime/cgo/libcgo.h.
const yesTsanProlog = `
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
extern void __tsan_acquire(void*);
extern void __tsan_release(void*);
+__attribute__ ((unused))
static void _cgo_tsan_acquire() {
__tsan_acquire(&_cgo_sync);
}
+__attribute__ ((unused))
static void _cgo_tsan_release() {
__tsan_release(&_cgo_sync);
}
ThreadStart ts;
ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
free(v);
+ _cgo_tsan_release();
/*
* Set specific keys.
ThreadStart *ts;
/* Make our own copy that can persist after we return. */
+ _cgo_tsan_acquire();
ts = malloc(sizeof *ts);
+ _cgo_tsan_release();
if(ts == nil) {
fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
abort();
uintptr_t Context;
};
extern void (*x_cgo_context_function)(struct context_arg*);
+
+/*
+ * TSAN support. This is only useful when building with
+ * CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
+ */
+#undef CGO_TSAN
+#if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+# define CGO_TSAN
+# endif
+#elif defined(__SANITIZE_THREAD__)
+# define CGO_TSAN
+#endif
+
+#ifdef CGO_TSAN
+
+// These must match the definitions in yesTsanProlog in cmd/cgo/out.go.
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+ __tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+ __tsan_release(&_cgo_sync);
+}
+
+#else // !defined(CGO_TSAN)
+
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+
+#endif // !defined(CGO_TSAN)