aboutsummaryrefslogtreecommitdiff
path: root/contrib/compiler-rt/lib/tsan/go/test.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/compiler-rt/lib/tsan/go/test.c')
-rw-r--r--contrib/compiler-rt/lib/tsan/go/test.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/tsan/go/test.c b/contrib/compiler-rt/lib/tsan/go/test.c
new file mode 100644
index 000000000000..c484774caeb9
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/go/test.c
@@ -0,0 +1,106 @@
+//===-- test.c ------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanity test for Go runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void __tsan_init(void **thr, void **proc, void (*cb)(long, void*));
+void __tsan_fini();
+void __tsan_map_shadow(void *addr, unsigned long size);
+void __tsan_go_start(void *thr, void **chthr, void *pc);
+void __tsan_go_end(void *thr);
+void __tsan_proc_create(void **pproc);
+void __tsan_proc_destroy(void *proc);
+void __tsan_proc_wire(void *proc, void *thr);
+void __tsan_proc_unwire(void *proc, void *thr);
+void __tsan_read(void *thr, void *addr, void *pc);
+void __tsan_write(void *thr, void *addr, void *pc);
+void __tsan_func_enter(void *thr, void *pc);
+void __tsan_func_exit(void *thr);
+void __tsan_malloc(void *thr, void *pc, void *p, unsigned long sz);
+void __tsan_free(void *p, unsigned long sz);
+void __tsan_acquire(void *thr, void *addr);
+void __tsan_release(void *thr, void *addr);
+void __tsan_release_merge(void *thr, void *addr);
+
+void *current_proc;
+
+void symbolize_cb(long cmd, void *ctx) {
+ switch (cmd) {
+ case 0:
+ if (current_proc == 0)
+ abort();
+ *(void**)ctx = current_proc;
+ }
+}
+
+/*
+ * See lib/tsan/rtl/tsan_platform.h for details of what the memory layout
+ * of Go programs looks like. To prevent running over existing mappings,
+ * we pick an address slightly inside the Go heap region.
+ */
+void *go_heap = (void *)0xC011110000;
+char *buf0;
+
+void foobar() {}
+void barfoo() {}
+
+int main(void) {
+ void *thr0 = 0;
+ void *proc0 = 0;
+ __tsan_init(&thr0, &proc0, symbolize_cb);
+ current_proc = proc0;
+
+ // Allocate something resembling a heap in Go.
+ buf0 = mmap(go_heap, 16384, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
+ if (buf0 == MAP_FAILED) {
+ fprintf(stderr, "failed to allocate Go-like heap at %p; errno %d\n",
+ go_heap, errno);
+ return 1;
+ }
+ char *buf = (char*)((unsigned long)buf0 + (64<<10) - 1 & ~((64<<10) - 1));
+ __tsan_map_shadow(buf, 4096);
+ __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10);
+ __tsan_free(buf, 10);
+ __tsan_func_enter(thr0, (char*)&main + 1);
+ __tsan_malloc(thr0, (char*)&barfoo + 1, buf, 10);
+ __tsan_release(thr0, buf);
+ __tsan_release_merge(thr0, buf);
+ void *thr1 = 0;
+ __tsan_go_start(thr0, &thr1, (char*)&barfoo + 1);
+ void *thr2 = 0;
+ __tsan_go_start(thr0, &thr2, (char*)&barfoo + 1);
+ __tsan_func_exit(thr0);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_func_enter(thr1, (char*)&foobar + 1);
+ __tsan_write(thr1, buf, (char*)&barfoo + 1);
+ __tsan_acquire(thr1, buf);
+ __tsan_func_exit(thr1);
+ __tsan_func_exit(thr1);
+ __tsan_go_end(thr1);
+ void *proc1 = 0;
+ __tsan_proc_create(&proc1);
+ current_proc = proc1;
+ __tsan_func_enter(thr2, (char*)&foobar + 1);
+ __tsan_read(thr2, buf, (char*)&barfoo + 1);
+ __tsan_free(buf, 10);
+ __tsan_func_exit(thr2);
+ __tsan_go_end(thr2);
+ __tsan_proc_destroy(proc1);
+ current_proc = proc0;
+ __tsan_fini();
+ return 0;
+}