diff mbox

New tsan tests.

Message ID 52A83A93.7020903@partner.samsung.com
State New
Headers show

Commit Message

max Dec. 11, 2013, 10:12 a.m. UTC
Hi all,

I've added new  tests for tsan from LLVM.

Tested on x86_64.

Ok to commit?

-Maxim
2013-12-11  Max Ostapenko  <m.ostapenko@partner.samsung.com>

	* c-c++-common/tsan/free_race2.c: New file.
	* c-c++-common/tsan/race_on_barrier2.c: New file.
	* c-c++-common/tsan/race_on_mutex.c: New file.
	* c-c++-common/tsan/race_on_mutex2.c: New file.
	* c-c++-common/tsan/simple_race.c: New file.
	* c-c++-common/tsan/simple_stack.c: New file.
	* g++.dg/tsan/aligned_vs_unaligned_race.C: New file.
	* g++.dg/tsan/atomic_free.C: New file.
	* g++.dg/tsan/atomic_free2.C: New file.
	* g++.dg/tsan/benign_race.C: New file.
	* g++.dg/tsan/cond_race.C: New file.
	* g++.dg/tsan/default_options.C: New file.
	* g++.dg/tsan/fd_close_norace.C: New file.
	* g++.dg/tsan/fd_close_norace2.C: New file.
	* g++-dg/tsan/tsan.exp: Modified to run additional C++ tests.

Comments

Jakub Jelinek Dec. 11, 2013, 10:23 a.m. UTC | #1
On Wed, Dec 11, 2013 at 02:12:35PM +0400, Maxim Ostapenko wrote:
> I've added new  tests for tsan from LLVM.
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <stdint.h>
> +
> +uint64_t Global[2];
> +
> +void *Thread1(void *x) {
> +  Global[1]++;
> +  return NULL;
> +}
> +
> +void *Thread2(void *x) {
> +  char *p1 = reinterpret_cast<char *>(&Global[0]);
> +  uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);

This test would fail on strict alignment targets.  Right now tsan
is supported only on x86_64-linux, so this isn't fatal right now, but
something to consider for the future.  Why is the test C++ only though?
Just replace the reinterpret_cast stuff with normal C cast?

> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tsan/benign_race.C
> @@ -0,0 +1,40 @@
> +/* { dg-do run } */
> +
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +
> +int Global;
> +int WTFGlobal;

Again, why C++ only?  Just guard the extern "C" { and } with #ifdef __cplusplus.

> +
> +extern "C" {
> +void AnnotateBenignRaceSized(const char *f, int l,
> +                             void *mem, unsigned int size, const char *desc);
> +void WTFAnnotateBenignRaceSized(const char *f, int l,
> +                                void *mem, unsigned int size,
> +                                const char *desc);
> +}

> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tsan/default_options.C
> @@ -0,0 +1,34 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "tsan" } */
> +
> +#include <pthread.h>
> +#include <stdio.h>
> +
> +extern "C" const char *__tsan_default_options() {
> +  return "report_bugs=0";

Similarly.

> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tsan/fd_close_norace.C
> @@ -0,0 +1,32 @@
> +/* { dg-do run } */
> +
> +#include <pthread.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +void *Thread1(void *x) {
> +  int f = open("/dev/random", O_RDONLY);
> +  close(f);
> +  return NULL;
> +}
> +
> +void *Thread2(void *x) {
> +  sleep(1);
> +  int f = open("/dev/random", O_RDONLY);
> +  close(f);
> +  return NULL;
> +}
> +
> +int main() {
> +  pthread_t t[2];
> +  pthread_create(&t[0], NULL, Thread1, NULL);
> +  pthread_create(&t[1], NULL, Thread2, NULL);
> +  pthread_join(t[0], NULL);
> +  pthread_join(t[1], NULL);
> +  printf("OK\n");
> +}

Ditto.  Is the only non-C thing here the missing return 0; from main?

> +
> +/* { dg-prune-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
> diff --git a/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C b/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C
> new file mode 100644
> index 0000000..f2d394c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C

Likewise.

	Jakub
Yury Gribov Dec. 11, 2013, 11:05 a.m. UTC | #2
> This test would fail on strict alignment targets.

Ok, we'll throw in a dg-skip-if.

 > Why is the test C++ only though?
 > Again, why C++ only?
 > Ditto.
 > Likewise.

I think main reason is having same versions of code with Clang. I had an 
impression that minimization of changes would be preferred and C vs. C++ 
should not make much difference for TSan anyway.

We can convert the tests if necessary though.

-Y
Jakub Jelinek Dec. 11, 2013, 11:07 a.m. UTC | #3
On Wed, Dec 11, 2013 at 03:05:22PM +0400, Yury Gribov wrote:
> > This test would fail on strict alignment targets.
> 
> Ok, we'll throw in a dg-skip-if.
> 
> > Why is the test C++ only though?
> > Again, why C++ only?
> > Ditto.
> > Likewise.
> 
> I think main reason is having same versions of code with Clang. I
> had an impression that minimization of changes would be preferred
> and C vs. C++ should not make much difference for TSan anyway.
> 
> We can convert the tests if necessary though.

I guess I can live with it as is, just was wondering why the tests
were written so carelessly that when they don't really need to test
any C++ features they are still written in C++.

	Jakub
Yury Gribov Dec. 11, 2013, 11:12 a.m. UTC | #4
> I guess I can live with it as is, just was wondering why the tests
 > were written so carelessly that when they don't really need to test
 > any C++ features they are still written in C++.

Adding Kostya to comment.

-Y
Konstantin Serebryany Dec. 11, 2013, 11:21 a.m. UTC | #5
What's wrong with C++?  :)
Upstream we have 16 .c tests and 106 .cc tests in
compiler-rt/lib/tsan/lit_tests.
We typically prefer .cc because imo C++ is a better language (even
when using what looks like the C subset).
But we need some .c tests to make sure that tsan still works w/o C++ run-time.

--kcc

On Wed, Dec 11, 2013 at 3:12 PM, Yury Gribov <y.gribov@samsung.com> wrote:
>> I guess I can live with it as is, just was wondering why the tests
>> were written so carelessly that when they don't really need to test
>> any C++ features they are still written in C++.
>
> Adding Kostya to comment.
>
> -Y
Jakub Jelinek Dec. 11, 2013, 11:27 a.m. UTC | #6
On Wed, Dec 11, 2013 at 03:21:32PM +0400, Konstantin Serebryany wrote:
> What's wrong with C++?  :)
> Upstream we have 16 .c tests and 106 .cc tests in
> compiler-rt/lib/tsan/lit_tests.
> We typically prefer .cc because imo C++ is a better language (even

That is a matter of opinion.

> when using what looks like the C subset).

The question is why don't you limit to the subset of the two languages
when it doesn't cost anything.  As I've mentioned on the patch, some of
the tests were C++ only (well, also C99) just because there wasn't return 0;
in main, others just because they used reinterpret_cast instead of C cast
where it didn't result in any advantage.  Some just because they used
new instead of malloc, though in this case I can understand that you might
want to test how is operator new instrumented.

	Jakub
Konstantin Serebryany Dec. 11, 2013, 11:35 a.m. UTC | #7
On Wed, Dec 11, 2013 at 3:27 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Dec 11, 2013 at 03:21:32PM +0400, Konstantin Serebryany wrote:
>> What's wrong with C++?  :)
>> Upstream we have 16 .c tests and 106 .cc tests in
>> compiler-rt/lib/tsan/lit_tests.
>> We typically prefer .cc because imo C++ is a better language (even
>
> That is a matter of opinion.

Of course! (I did say "imo")

>
>> when using what looks like the C subset).
>
> The question is why don't you limit to the subset of the two languages
> when it doesn't cost anything.

Mostly because of my (our) opinion above. :)
GCC test suite may have more .c tests than .cc tests; I don't have an
opinion here.
We need some C++specific tests (e.g. with operator new) and we need at
least one C test.

--kcc

>  As I've mentioned on the patch, some of
> the tests were C++ only (well, also C99) just because there wasn't return 0;
> in main, others just because they used reinterpret_cast instead of C cast
> where it didn't result in any advantage.  Some just because they used
> new instead of malloc, though in this case I can understand that you might
> want to test how is operator new instrumented.
>
>         Jakub
Jakub Jelinek Dec. 11, 2013, 12:06 p.m. UTC | #8
On Wed, Dec 11, 2013 at 03:35:37PM +0400, Konstantin Serebryany wrote:
> >> when using what looks like the C subset).
> >
> > The question is why don't you limit to the subset of the two languages
> > when it doesn't cost anything.
> 
> Mostly because of my (our) opinion above. :)
> GCC test suite may have more .c tests than .cc tests; I don't have an
> opinion here.
> We need some C++specific tests (e.g. with operator new) and we need at
> least one C test.

In the GCC testsuite, you can put tests that are written in the common
subset of C and C++ that you want to test by both frontends into
c-c++-common (they even can have different expected errors etc. through
{ target c } or { target c++ }), you can use #ifdef __cplusplus in the tests
too.  Anyway, let's keep the current tests as is, the patch is ok for trunk,
and if in the future you wouldn't mind making more tests written in the
common subset of C/C++, it would be certainly appreciated.

	Jakub
max Dec. 12, 2013, 11:46 a.m. UTC | #9
> Anyway, let's keep the current tests as is, the patch is ok for trunk.

Commited in 205925.
diff mbox

Patch

diff --git a/gcc/testsuite/c-c++-common/tsan/free_race2.c b/gcc/testsuite/c-c++-common/tsan/free_race2.c
new file mode 100644
index 0000000..3c15d2d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/free_race2.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <stdlib.h>
+
+void __attribute__((noinline)) foo(int *mem) {
+  free(mem);
+}
+
+void __attribute__((noinline)) bar(int *mem) {
+  mem[0] = 42;
+}
+
+int main() {
+  int *mem = (int*)malloc(100);
+  foo(mem);
+  bar(mem);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "  Write of size 4.* by main thread:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 bar.*" } */
+/* { dg-output "    #1 main .*" } */
+/* { dg-output "  Previous write of size 8 at .* by main thread:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 free .*" } */
+/* { dg-output "    #\(1|2\) foo.*(\n|\r\n|\r)" } */
+/* { dg-output "    #\(2|3\) main .*" } */
+
diff --git a/gcc/testsuite/c-c++-common/tsan/race_on_barrier2.c b/gcc/testsuite/c-c++-common/tsan/race_on_barrier2.c
new file mode 100644
index 0000000..9576c67
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/race_on_barrier2.c
@@ -0,0 +1,33 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+  if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+    pthread_barrier_destroy(&B);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+    pthread_barrier_destroy(&B);
+  return NULL;
+}
+
+int main() {
+  pthread_barrier_init(&B, 0, 2);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  Thread2(0);
+  pthread_join(t, NULL);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/race_on_mutex.c b/gcc/testsuite/c-c++-common/tsan/race_on_mutex.c
new file mode 100644
index 0000000..f112d09
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/race_on_mutex.c
@@ -0,0 +1,44 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_mutex_t Mtx;
+int Global;
+
+void *Thread1(void *x) {
+  pthread_mutex_init(&Mtx, 0);
+  pthread_mutex_lock(&Mtx);
+  Global = 42;
+  pthread_mutex_unlock(&Mtx);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  sleep(1);
+  pthread_mutex_lock(&Mtx);
+  Global = 43;
+  pthread_mutex_unlock(&Mtx);
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  pthread_mutex_destroy(&Mtx);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output "  Atomic read of size 1 at .* by thread T2:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 pthread_mutex_lock.*" } */
+/* { dg-output "    #1 Thread2.* .*(race_on_mutex.c:22|\\?{2}:0) (.*)" } */
+/* { dg-output "  Previous write of size 1 at .* by thread T1:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 pthread_mutex_init .* (.)*" } */
+/* { dg-output "    #1 Thread1.* .*(race_on_mutex.c:13|\\?{2}:0) .*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/race_on_mutex2.c b/gcc/testsuite/c-c++-common/tsan/race_on_mutex2.c
new file mode 100644
index 0000000..d8a6980
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/race_on_mutex2.c
@@ -0,0 +1,26 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+  pthread_mutex_lock((pthread_mutex_t*)x);
+  pthread_mutex_unlock((pthread_mutex_t*)x);
+  return 0;
+}
+
+int main() {
+  pthread_mutex_t Mtx;
+  pthread_mutex_init(&Mtx, 0);
+  pthread_t t;
+  pthread_create(&t, 0, Thread, &Mtx);
+  sleep(1);
+  pthread_mutex_destroy(&Mtx);
+  pthread_join(t, 0);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/simple_race.c b/gcc/testsuite/c-c++-common/tsan/simple_race.c
new file mode 100644
index 0000000..24b88e8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/simple_race.c
@@ -0,0 +1,28 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+  Global = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/simple_stack.c b/gcc/testsuite/c-c++-common/tsan/simple_stack.c
new file mode 100644
index 0000000..e92d010
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/simple_stack.c
@@ -0,0 +1,66 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+  Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+  volatile int tmp = 42; (void)tmp;
+  foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+  volatile int v = Global; (void)v;
+}
+
+void __attribute__((noinline)) bar2() {
+  volatile int tmp = 42; (void)tmp;
+  foo2();
+}
+
+void *Thread1(void *x) {
+  sleep(1);
+  bar1();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  bar2();
+  return NULL;
+}
+
+void StartThread(pthread_t *t, void *(*f)(void*)) {
+  pthread_create(t, NULL, f, NULL);
+}
+
+int main() {
+  pthread_t t[2];
+  StartThread(&t[0], Thread1);
+  StartThread(&t[1], Thread2);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*" } */
+/* { dg-output "  Write of size 4 at .* by thread T1:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 foo1.* .*(simple_stack.c:11|\\?{2}:0) (.*)" } */
+/* { dg-output "    #1 bar1.* .*(simple_stack.c:16|\\?{2}:0) (.*)" } */
+/* { dg-output "    #2 Thread1.* .*(simple_stack.c:30|\\?{2}:0) (.*)" } */
+/* { dg-output "  Previous read of size 4 at .* by thread T2:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 foo2.* .*(simple_stack.c:20|\\?{2}:0) (.*)" } */
+/* { dg-output "    #1 bar2.* .*(simple_stack.c:25|\\?{2}:0) (.*)" } */
+/* { dg-output "    #2 Thread2.* .*(simple_stack.c:35|\\?{2}:0) (.*)" } */
+/* { dg-output "  Thread T1 \\(tid=.*, running\\) created by main thread at:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 pthread_create .* (.*)" } */
+/* { dg-output "    #1 StartThread.* .*(simple_stack.c:40|\\?{2}:0) (.*)" } */
+/* { dg-output "  Thread T2 (.*) created by main thread at:(\n|\r\n|\r)" } */
+/* { dg-output "    #0 pthread_create .* (.*)" } */
+/* { dg-output "    #1 StartThread.* .*(simple_stack.c:40|\\?{2}:0) (.*)" } */
diff --git a/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C b/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C
new file mode 100644
index 0000000..caf0942
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C
@@ -0,0 +1,31 @@ 
+/* { dg-do run } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+
+uint64_t Global[2];
+
+void *Thread1(void *x) {
+  Global[1]++;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  char *p1 = reinterpret_cast<char *>(&Global[0]);
+  uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
+  (*p4)++;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("Pass\n");
+  /* { dg-prune-output "ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+  /* { dg-output "Pass.*" } */
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/tsan/atomic_free.C b/gcc/testsuite/g++.dg/tsan/atomic_free.C
new file mode 100644
index 0000000..afaad77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/atomic_free.C
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+  __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+  return 0;
+}
+
+int main() {
+  int *a = new int(0);
+  pthread_t t;
+  pthread_create(&t, 0, Thread, a);
+  sleep(1);
+  delete a;
+  pthread_join(t, 0);
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/g++.dg/tsan/atomic_free2.C b/gcc/testsuite/g++.dg/tsan/atomic_free2.C
new file mode 100644
index 0000000..7ccaa1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/atomic_free2.C
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *a) {
+  sleep(1);
+  __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST);
+  return 0;
+}
+
+int main() {
+  int *a = new int(0);
+  pthread_t t;
+  pthread_create(&t, 0, Thread, a);
+  delete a;
+  pthread_join(t, 0);
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/g++.dg/tsan/benign_race.C b/gcc/testsuite/g++.dg/tsan/benign_race.C
new file mode 100644
index 0000000..d67b31b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/benign_race.C
@@ -0,0 +1,40 @@ 
+/* { dg-do run } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+int WTFGlobal;
+
+extern "C" {
+void AnnotateBenignRaceSized(const char *f, int l,
+                             void *mem, unsigned int size, const char *desc);
+void WTFAnnotateBenignRaceSized(const char *f, int l,
+                                void *mem, unsigned int size,
+                                const char *desc);
+}
+
+
+void *Thread(void *x) {
+  Global = 42;
+  WTFGlobal = 142;
+  return 0;
+}
+
+int main() {
+  AnnotateBenignRaceSized(__FILE__, __LINE__,
+                          &Global, sizeof(Global), "Race on Global");
+  WTFAnnotateBenignRaceSized(__FILE__, __LINE__,
+                             &WTFGlobal, sizeof(WTFGlobal),
+                             "Race on WTFGlobal");
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  sleep(1);
+  Global = 43;
+  WTFGlobal = 143;
+  pthread_join(t, 0);
+  printf("OK\n");
+}
+
+/* { dg-prune-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/g++.dg/tsan/cond_race.C b/gcc/testsuite/g++.dg/tsan/cond_race.C
new file mode 100644
index 0000000..d28912f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/cond_race.C
@@ -0,0 +1,37 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+/* { dg-output "ThreadSanitizer: data race.*" } */
+/* { dg-output "pthread_cond_signal.*" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+struct Ctx {
+  pthread_mutex_t m;
+  pthread_cond_t c;
+  bool done;
+};
+
+void *thr(void *p) {
+  Ctx *c = (Ctx*)p;
+  pthread_mutex_lock(&c->m);
+  c->done = true;
+  pthread_mutex_unlock(&c->m);
+  pthread_cond_signal(&c->c);
+  return 0;
+}
+
+int main() {
+  Ctx *c = new Ctx();
+  pthread_mutex_init(&c->m, 0);
+  pthread_cond_init(&c->c, 0);
+  pthread_t th;
+  pthread_create(&th, 0, thr, c);
+  pthread_mutex_lock(&c->m);
+  while (!c->done)
+    pthread_cond_wait(&c->c, &c->m);
+  pthread_mutex_unlock(&c->m);
+  delete c;
+  pthread_join(th, 0);
+}
diff --git a/gcc/testsuite/g++.dg/tsan/default_options.C b/gcc/testsuite/g++.dg/tsan/default_options.C
new file mode 100644
index 0000000..b688abf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/default_options.C
@@ -0,0 +1,34 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+
+extern "C" const char *__tsan_default_options() {
+  return "report_bugs=0";
+}
+
+int Global;
+
+void *Thread1(void *x) {
+  Global = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  fprintf(stderr, "DONE\n");
+  return 0;
+}
+
+/* { dg-prune-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output "DONE" } */
diff --git a/gcc/testsuite/g++.dg/tsan/fd_close_norace.C b/gcc/testsuite/g++.dg/tsan/fd_close_norace.C
new file mode 100644
index 0000000..a31428a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/fd_close_norace.C
@@ -0,0 +1,32 @@ 
+/* { dg-do run } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void *Thread1(void *x) {
+  int f = open("/dev/random", O_RDONLY);
+  close(f);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  sleep(1);
+  int f = open("/dev/random", O_RDONLY);
+  close(f);
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  printf("OK\n");
+}
+
+/* { dg-prune-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C b/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C
new file mode 100644
index 0000000..f2d394c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/fd_close_norace2.C
@@ -0,0 +1,31 @@ 
+/* { dg-do run } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int pipes[2];
+
+void *Thread(void *x) {
+  // wait for shutown signal
+  while (read(pipes[0], &x, 1) != 1) {
+  }
+  close(pipes[0]);
+  close(pipes[1]);
+  return 0;
+}
+
+int main() {
+  if (pipe(pipes))
+    return 1;
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  // send shutdown signal
+  while (write(pipes[1], &t, 1) != 1) {
+  }
+  pthread_join(t, 0);
+  printf("OK\n");
+}
+
+/* { dg-prune-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output "OK" } */
diff --git a/gcc/testsuite/g++.dg/tsan/tsan.exp b/gcc/testsuite/g++.dg/tsan/tsan.exp
index 40c28ce..9bcf6cc 100644
--- a/gcc/testsuite/g++.dg/tsan/tsan.exp
+++ b/gcc/testsuite/g++.dg/tsan/tsan.exp
@@ -37,7 +37,7 @@  set-torture-options [list \
 if [tsan_init] {
 
 # Main loop.
-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/tsan/*.c]] ""
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/tsan/*.c]] ""
 
 }