1/*
2  This file is part of Valgrind, a dynamic binary instrumentation
3  framework.
4
5  Copyright (C) 2008-2008 Google Inc
6     opensource@google.com
7
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21  02111-1307, USA.
22
23  The GNU General Public License is contained in the file COPYING.
24*/
25
26/* Author: Konstantin Serebryany <opensource@google.com>
27
28 This file contains a set of unit tests for a data race detection tool.
29
30 These tests can be compiled with pthreads (default) or
31 with any other library that supports threads, locks, cond vars, etc.
32
33*/
34#ifdef WIN32
35#error "Don't build this file on Windows!"
36#endif
37
38#include <fcntl.h>
39#include <fenv.h>
40#include <queue>
41#include <signal.h>
42#include <stdlib.h>
43#include <string>
44#include <vector>
45#include <unistd.h>
46
47#ifdef OS_linux
48# include <sys/epoll.h>
49#endif  // OS_linux
50
51#include "test_utils.h"
52#include <gtest/gtest.h>
53#include "gtest_fixture_injection.h"
54
55static CondVar CV;
56static int     COND = 0;
57
58// test11: FP. Synchronization via CondVar, 2 workers. {{{1
59// This test is properly synchronized, but currently (Dec 2007)
60// helgrind reports a false positive.
61//
62// Parent:                              Worker1, Worker2:
63// 1. Start(workers)                    a. read(GLOB)
64// 2. MU.Lock()                         b. MU.Lock()
65// 3. while(COND != 2)        /-------- c. CV.Signal()
66//      CV.Wait(&MU) <-------/          d. MU.Unlock()
67// 4. MU.Unlock()
68// 5. write(GLOB)
69//
70namespace test11 {
71int     GLOB = 0;
72Mutex   MU;
73void Worker() {
74  usleep(200000);
75  CHECK(GLOB != 777);
76
77  MU.Lock();
78  COND++;
79  CV.Signal();
80  MU.Unlock();
81}
82
83void Parent() {
84  COND = 0;
85
86  MyThreadArray t(Worker, Worker);
87  t.Start();
88
89  MU.Lock();
90  while(COND != 2) {
91    CV.Wait(&MU);
92  }
93  MU.Unlock();
94
95  GLOB = 2;
96
97  t.Join();
98}
99
100TEST(NegativeTests, test11) {
101//  ANNOTATE_EXPECT_RACE(&GLOB, "test11. FP. Fixed by MSMProp1.");
102  printf("test11: negative\n");
103  Parent();
104  printf("\tGLOB=%d\n", GLOB);
105}
106}  // namespace test11
107
108
109// test75: TN. Test for sem_post, sem_wait, sem_trywait. {{{1
110namespace test75 {
111int     GLOB = 0;
112sem_t   sem[2];
113
114void Poster() {
115  GLOB = 1;
116  sem_post(&sem[0]);
117  sem_post(&sem[1]);
118}
119
120void Waiter() {
121  sem_wait(&sem[0]);
122  CHECK(GLOB==1);
123}
124void TryWaiter() {
125  usleep(500000);
126  sem_trywait(&sem[1]);
127  CHECK(GLOB==1);
128}
129
130TEST(NegativeTests, test75) {
131#ifndef NO_UNNAMED_SEM
132  sem_init(&sem[0], 0, 0);
133  sem_init(&sem[1], 0, 0);
134
135  printf("test75: negative\n");
136  {
137    MyThreadArray t(Poster, Waiter);
138    t.Start();
139    t.Join();
140  }
141  GLOB = 2;
142  {
143    MyThreadArray t(Poster, TryWaiter);
144    t.Start();
145    t.Join();
146  }
147  printf("\tGLOB=%d\n", GLOB);
148
149  sem_destroy(&sem[0]);
150  sem_destroy(&sem[1]);
151#endif // NO_UNNAMED_SEM
152}
153}  // namespace test75
154
155
156// test98: Synchronization via read/write (or send/recv). {{{1
157namespace test98 {
158// The synchronization here is done by a pair of read/write calls
159// that create a happens-before arc. Same may be done with send/recv.
160// Such synchronization is quite unusual in real programs
161// (why would one synchronizae via a file or socket?), but
162// quite possible in unittests where one threads runs for producer
163// and one for consumer.
164//
165// A race detector has to create a happens-before arcs for
166// {read,send}->{write,recv} even if the file descriptors are different.
167//
168int     GLOB = 0;
169int fd_out = -1;
170int fd_in  = -1;
171
172void Writer() {
173  usleep(1000);
174  GLOB = 1;
175  const char *str = "Hey there!\n";
176  const int size = strlen(str) + 1;
177  CHECK(size == write(fd_out, str, size));
178}
179
180void Reader() {
181  char buff[100];
182  while (read(fd_in, buff, 100) == 0)
183    sleep(1);
184  printf("read: %s\n", buff);
185  GLOB = 2;
186}
187
188#ifndef __APPLE__
189// Tsan for Mac OS is missing the unlink() syscall handler.
190// TODO(glider): add the syscall handler to Valgrind.
191TEST(NegativeTests, test98) {
192  printf("test98: negative, synchronization via I/O\n");
193  char in_name[100];
194  char out_name[100];
195  // we open two files, on for reading and one for writing,
196  // but the files are actually the same (symlinked).
197  sprintf(in_name,  "/tmp/racecheck_unittest_in.%d", getpid());
198  sprintf(out_name, "/tmp/racecheck_unittest_out.%d", getpid());
199  fd_out = creat(out_name, O_WRONLY | S_IRWXU);
200  CHECK(0 == symlink(out_name, in_name));
201  fd_in  = open(in_name, 0, O_RDONLY);
202  CHECK(fd_out >= 0);
203  CHECK(fd_in  >= 0);
204  MyThreadArray t(Writer, Reader);
205  t.Start();
206  t.Join();
207  printf("\tGLOB=%d\n", GLOB);
208  // cleanup
209  close(fd_in);
210  close(fd_out);
211  unlink(in_name);
212  unlink(out_name);
213}
214#endif  // __APPLE__
215}  // namespace test98
216
217
218namespace NegativeTests_PthreadOnce {  // {{{1
219int     *GLOB = NULL;
220static pthread_once_t once = PTHREAD_ONCE_INIT;
221void Init() {
222  GLOB = new int;
223  ANNOTATE_TRACE_MEMORY(GLOB);
224  *GLOB = 777;
225}
226
227void Worker0() {
228  pthread_once(&once, Init);
229}
230void Worker1() {
231  usleep(100000);
232  pthread_once(&once, Init);
233  CHECK(*GLOB == 777);
234}
235
236
237TEST(NegativeTests, PthreadOnceTest) {
238  MyThreadArray t(Worker0, Worker1, Worker1, Worker1);
239  t.Start();
240  t.Join();
241  printf("\tGLOB=%d\n", *GLOB);
242}
243}  // namespace
244
245
246// test110: TP. Simple races with stack, global and heap objects. {{{1
247namespace test110 {
248int        GLOB = 0;
249static int STATIC;
250
251char       *STACK = 0;
252
253int       *MALLOC;
254int       *CALLOC;
255int       *REALLOC;
256int       *VALLOC;
257int       *PVALLOC;
258int       *MEMALIGN;
259int       *POSIX_MEMALIGN;
260int       *MMAP;
261
262int       *NEW;
263int       *NEW_ARR;
264
265void Worker() {
266  GLOB++;
267  STATIC++;
268
269  (*STACK)++;
270
271  (*MALLOC)++;
272  (*CALLOC)++;
273  (*REALLOC)++;
274  (*VALLOC)++;
275  (*PVALLOC)++;
276  (*MEMALIGN)++;
277  (*POSIX_MEMALIGN)++;
278  (*MMAP)++;
279
280  (*NEW)++;
281  (*NEW_ARR)++;
282}
283TEST(PositiveTests, test110) {
284  printf("test110: positive (race on a stack object)\n");
285
286  char x = 0;
287  STACK = &x;
288
289  MALLOC = (int*)malloc(sizeof(int));
290  CALLOC = (int*)calloc(1, sizeof(int));
291  REALLOC = (int*)realloc(NULL, sizeof(int));
292  VALLOC = (int*)valloc(sizeof(int));
293  PVALLOC = (int*)valloc(sizeof(int));  // TODO: pvalloc breaks helgrind.
294  MEMALIGN = (int*)memalign(64, sizeof(int));
295  CHECK(0 == posix_memalign((void**)&POSIX_MEMALIGN, 64, sizeof(int)));
296  MMAP = (int*)mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE,
297                    MAP_PRIVATE | MAP_ANON, -1, 0);
298
299  NEW     = new int;
300  NEW_ARR = new int[10];
301
302
303  ANNOTATE_EXPECT_RACE(STACK, "real race on stack object");
304  ANNOTATE_EXPECT_RACE(&GLOB, "real race on global object");
305  ANNOTATE_EXPECT_RACE(&STATIC, "real race on a static global object");
306  ANNOTATE_EXPECT_RACE(MALLOC, "real race on a malloc-ed object");
307  ANNOTATE_EXPECT_RACE(CALLOC, "real race on a calloc-ed object");
308  ANNOTATE_EXPECT_RACE(REALLOC, "real race on a realloc-ed object");
309  ANNOTATE_EXPECT_RACE(VALLOC, "real race on a valloc-ed object");
310  ANNOTATE_EXPECT_RACE(PVALLOC, "real race on a pvalloc-ed object");
311  ANNOTATE_EXPECT_RACE(MEMALIGN, "real race on a memalign-ed object");
312  ANNOTATE_EXPECT_RACE(POSIX_MEMALIGN, "real race on a posix_memalign-ed object");
313  ANNOTATE_EXPECT_RACE(MMAP, "real race on a mmap-ed object");
314
315  ANNOTATE_EXPECT_RACE(NEW, "real race on a new-ed object");
316  ANNOTATE_EXPECT_RACE(NEW_ARR, "real race on a new[]-ed object");
317
318  MyThreadArray t(Worker, Worker, Worker);
319  t.Start();
320  t.Join();
321  printf("\tSTACK=%d\n", *STACK);
322  CHECK(GLOB <= 3);
323  CHECK(STATIC <= 3);
324
325  free(MALLOC);
326  free(CALLOC);
327  free(REALLOC);
328  free(VALLOC);
329  free(PVALLOC);
330  free(MEMALIGN);
331  free(POSIX_MEMALIGN);
332  munmap(MMAP, sizeof(int));
333  delete NEW;
334  delete [] NEW_ARR;
335}
336}  // namespace test110
337
338
339// test115: TN. sem_open. {{{1
340namespace    test115 {
341int tid = 0;
342Mutex mu;
343const char *kSemName = "drt-test-sem";
344
345int GLOB = 0;
346
347sem_t *DoSemOpen() {
348  // TODO: there is some race report inside sem_open
349  // for which suppressions do not work... (???)
350  ANNOTATE_IGNORE_WRITES_BEGIN();
351  sem_t *sem = sem_open(kSemName, O_CREAT, 0600, 3);
352  ANNOTATE_IGNORE_WRITES_END();
353  return sem;
354}
355
356void Worker() {
357  mu.Lock();
358  int my_tid = tid++;
359  mu.Unlock();
360
361  if (my_tid == 0) {
362    GLOB = 1;
363  }
364
365  // if the detector observes a happens-before arc between
366  // sem_open and sem_wait, it will be silent.
367  sem_t *sem = DoSemOpen();
368  usleep(100000);
369  CHECK(sem != SEM_FAILED);
370  CHECK(sem_wait(sem) == 0);
371
372  if (my_tid > 0) {
373    CHECK(GLOB == 1);
374  }
375}
376
377#ifndef __APPLE__
378/* This test is disabled for Darwin because of the tricky implementation of
379 * sem_open on that platform: subsequent attempts to open an existing semafore
380 * create new ones. */
381TEST(NegativeTests, test115) {
382  printf("test115: stab (sem_open())\n");
383
384  // just check that sem_open is not completely broken
385  sem_unlink(kSemName);
386  sem_t* sem = DoSemOpen();
387  CHECK(sem != SEM_FAILED);
388  CHECK(sem_wait(sem) == 0);
389  sem_unlink(kSemName);
390
391  // check that sem_open and sem_wait create a happens-before arc.
392  MyThreadArray t(Worker, Worker, Worker);
393  t.Start();
394  t.Join();
395  // clean up
396  sem_unlink(kSemName);
397}
398#endif  // __APPLE__
399}  // namespace test115
400
401
402// test122 TP: Simple test with RWLock {{{1
403namespace  test122 {
404int     VAR1 = 0;
405int     VAR2 = 0;
406RWLock mu;
407
408void WriteWhileHoldingReaderLock(int *p) {
409  usleep(100000);
410  ReaderLockScoped lock(&mu);  // Reader lock for writing. -- bug.
411  (*p)++;
412}
413
414void CorrectWrite(int *p) {
415  WriterLockScoped lock(&mu);
416  (*p)++;
417}
418
419void Thread1() { WriteWhileHoldingReaderLock(&VAR1); }
420void Thread2() { CorrectWrite(&VAR1); }
421void Thread3() { CorrectWrite(&VAR2); }
422void Thread4() { WriteWhileHoldingReaderLock(&VAR2); }
423
424
425TEST(PositiveTests, test122) {
426  printf("test122: positive (rw-lock)\n");
427  VAR1 = 0;
428  VAR2 = 0;
429  ANNOTATE_TRACE_MEMORY(&VAR1);
430  ANNOTATE_TRACE_MEMORY(&VAR2);
431  if (!Tsan_PureHappensBefore()) {
432    ANNOTATE_EXPECT_RACE_FOR_TSAN(&VAR1, "test122. TP. ReaderLock-ed while writing");
433    ANNOTATE_EXPECT_RACE_FOR_TSAN(&VAR2, "test122. TP. ReaderLock-ed while writing");
434  }
435  MyThreadArray t(Thread1, Thread2, Thread3, Thread4);
436  t.Start();
437  t.Join();
438}
439}  // namespace test122
440
441
442// test125 TN: Backwards lock (annotated). {{{1
443namespace test125 {
444// This test uses "Backwards mutex" locking protocol.
445// We take a *reader* lock when writing to a per-thread data
446// (GLOB[thread_num])  and we take a *writer* lock when we
447// are reading from the entire array at once.
448//
449// Such locking protocol is not understood by ThreadSanitizer's
450// hybrid state machine. So, you either have to use a pure-happens-before
451// detector ("tsan --pure-happens-before") or apply pure happens-before mode
452// to this particular lock by using ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&mu).
453
454const int n_threads = 3;
455RWLock   mu;
456int     GLOB[n_threads];
457
458int adder_num; // updated atomically.
459
460void Adder() {
461  int my_num = AtomicIncrement(&adder_num, 1) - 1;
462  CHECK(my_num >= 0);
463  CHECK(my_num < n_threads);
464
465  ReaderLockScoped lock(&mu);
466  GLOB[my_num]++;
467}
468
469void Aggregator() {
470  int sum = 0;
471  {
472    WriterLockScoped lock(&mu);
473    for (int i = 0; i < n_threads; i++) {
474      sum += GLOB[i];
475    }
476  }
477  printf("sum=%d\n", sum);
478}
479
480TEST(NegativeTests, test125) {
481  printf("test125: negative\n");
482
483  ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&mu);
484
485  // run Adders, then Aggregator
486  adder_num = 0;
487  {
488    MyThreadArray t(Adder, Adder, Adder, Aggregator);
489    t.Start();
490    t.Join();
491  }
492
493  // Run Aggregator first.
494  adder_num = 0;
495  {
496    MyThreadArray t(Aggregator, Adder, Adder, Adder);
497    t.Start();
498    t.Join();
499  }
500
501}
502}  // namespace test125
503
504
505namespace MmapTest {  // {{{1
506
507const int kMmapSize =  65536;
508
509void SubWorker() {
510  for (int i = 0; i < 500; i++) {
511    int *ptr = (int*)mmap(NULL, kMmapSize, PROT_READ | PROT_WRITE,
512                          MAP_PRIVATE | MAP_ANON, -1, 0);
513    *ptr = 42;
514    munmap(ptr, kMmapSize);
515  }
516}
517
518void Worker1() {
519  MyThreadArray t(SubWorker, SubWorker, SubWorker, SubWorker);
520  t.Start();
521  t.Join();
522}
523void Worker() {
524  MyThreadArray t(Worker1, Worker1, Worker1, Worker1);
525  t.Start();
526  t.Join();
527}
528
529TEST(NegativeTests, MmapTest) {
530  MyThreadArray t(Worker, Worker, Worker, Worker);
531  t.Start();
532  t.Join();
533}
534}  // namespace
535
536
537// A regression test for mmap/munmap handling in Pin.
538// If the tool misses munmap() calls it may report a false positive if two
539// threads map the same memory region.
540namespace MmapRegressionTest {  // {{{1
541
542const int kMmapSize =  65536;
543const uintptr_t kStartAddress = 0x10000;
544
545StealthNotification n1;
546
547void Worker() {
548    int *ptr = (int*)mmap((void*)kStartAddress, kMmapSize,
549                          PROT_READ | PROT_WRITE,
550                          MAP_PRIVATE | MAP_ANON, -1, 0);
551    *ptr = 42;
552    munmap(ptr, kMmapSize);
553}
554
555TEST(NegativeTests, MmapRegressionTest) {
556  MyThreadArray t(Worker, Worker);
557  t.Start();
558  t.Join();
559}
560
561}  // namespace
562
563// test136. Unlock twice. {{{1
564namespace test136 {
565TEST(LockTests, UnlockTwice) {
566  pthread_mutexattr_t attr;
567  CHECK(0 == pthread_mutexattr_init(&attr));
568  CHECK(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK));
569
570  pthread_mutex_t mu;
571  CHECK(0 == pthread_mutex_init(&mu, &attr));
572  CHECK(0 == pthread_mutex_lock(&mu));
573  CHECK(0 == pthread_mutex_unlock(&mu));
574  int ret_unlock = pthread_mutex_unlock(&mu);  // unlocking twice.
575  int ret_destroy = pthread_mutex_destroy(&mu);
576  printf("  pthread_mutex_unlock returned %d\n", ret_unlock);
577  printf("  pthread_mutex_destroy returned %d\n", ret_destroy);
578}
579}  // namespace test136
580
581
582// test141 FP. unlink/fopen, rmdir/opendir. {{{1
583namespace test141 {
584int GLOB1 = 0,
585    GLOB2 = 0;
586char *dir_name = NULL,
587     *filename = NULL;
588
589void Waker1() {
590  usleep(100000);
591  GLOB1 = 1;  // Write
592  // unlink deletes a file 'filename'
593  // which exits spin-loop in Waiter1().
594  printf("  Deleting file...\n");
595  CHECK(unlink(filename) == 0);
596}
597
598void Waiter1() {
599  FILE *tmp;
600  while ((tmp = fopen(filename, "r")) != NULL) {
601    fclose(tmp);
602    usleep(10000);
603  }
604  printf("  ...file has been deleted\n");
605  GLOB1 = 2;  // Write
606}
607
608void Waker2() {
609  usleep(100000);
610  GLOB2 = 1;  // Write
611  // rmdir deletes a directory 'dir_name'
612  // which exit spin-loop in Waker().
613  printf("  Deleting directory...\n");
614  CHECK(rmdir(dir_name) == 0);
615}
616
617void Waiter2() {
618  DIR *tmp;
619  while ((tmp = opendir(dir_name)) != NULL) {
620    closedir(tmp);
621    usleep(10000);
622  }
623  printf("  ...directory has been deleted\n");
624  GLOB2 = 2;
625}
626
627TEST(NegativeTests, test141) {
628  printf("test141: FP. unlink/fopen, rmdir/opendir.\n");
629
630  dir_name = strdup("/tmp/tsan-XXXXXX");
631  CHECK(mkdtemp(dir_name) != 0);
632
633  filename = strdup((std::string() + dir_name + "/XXXXXX").c_str());
634  const int fd = mkstemp(filename);
635  CHECK(fd >= 0);
636  close(fd);
637
638  MyThreadArray mta1(Waker1, Waiter1);
639  mta1.Start();
640  mta1.Join();
641
642  MyThreadArray mta2(Waker2, Waiter2);
643  mta2.Start();
644  mta2.Join();
645
646  free(filename);
647  filename = 0;
648  free(dir_name);
649  dir_name = 0;
650}
651}  // namespace test141
652
653
654// test146: TP. Unit test for RWLock::TryLock and RWLock::ReaderTryLock. {{{1
655namespace test146 {
656// Worker1 locks the globals for writing for a long time.
657// Worker2 tries to write to globals twice: without a writer lock and with it.
658// Worker3 tries to read from globals twice: without a reader lock and with it.
659int     GLOB1 = 0;
660char    padding1[64];
661int     GLOB2 = 0;
662char    padding2[64];
663int     GLOB3 = 0;
664char    padding3[64];
665int     GLOB4 = 0;
666RWLock  MU;
667StealthNotification n1, n2, n3, n4, n5;
668
669void Worker1() {
670  MU.Lock();
671  GLOB1 = 1;
672  GLOB2 = 1;
673  GLOB3 = 1;
674  GLOB4 = 1;
675  n1.signal();
676  n2.wait();
677  n3.wait();
678  MU.Unlock();
679  n4.signal();
680}
681
682void Worker2() {
683  n1.wait();
684  if (MU.TryLock()) CHECK(0);
685  else
686    GLOB1 = 2;
687  n2.signal();
688  n5.wait();
689  if (MU.TryLock()) {
690    GLOB2 = 2;
691    MU.Unlock();
692  } else {
693    CHECK(0);
694  }
695}
696
697void Worker3() {
698  n1.wait();
699  if (MU.ReaderTryLock()) CHECK(0);
700  else
701    printf("\treading GLOB3: %d\n", GLOB3);
702  n3.signal();
703  n4.wait();
704  if (MU.ReaderTryLock()) {
705    printf("\treading GLOB4: %d\n", GLOB4);
706    MU.ReaderUnlock();
707  } else {
708    CHECK(0);
709  }
710  n5.signal();
711}
712
713TEST(PositiveTests, test146) {
714  ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB1, "test146. TP: a data race on GLOB1.");
715  ANNOTATE_EXPECT_RACE_FOR_TSAN(&GLOB3, "test146. TP: a data race on GLOB3.");
716  ANNOTATE_TRACE_MEMORY(&GLOB1);
717  ANNOTATE_TRACE_MEMORY(&GLOB2);
718  ANNOTATE_TRACE_MEMORY(&GLOB3);
719  ANNOTATE_TRACE_MEMORY(&GLOB4);
720  printf("test146: positive\n");
721  MyThreadArray t(Worker1, Worker2, Worker3);
722  t.Start();
723  t.Join();
724  printf("\tGLOB1=%d\n", GLOB1);
725  printf("\tGLOB2=%d\n", GLOB2);
726  printf("\tGLOB3=%d\n", GLOB3);
727  printf("\tGLOB4=%d\n", GLOB4);
728}
729} // namespace test146
730
731namespace PositiveTests_CyclicBarrierTest {  // {{{1
732#ifndef NO_BARRIER
733// regression test for correct support of cyclic barrier.
734// This test was suggested by Julian Seward.
735// There is a race on L here between a1 and b1,
736// but a naive support of barrier makes us miss this race.
737pthread_barrier_t B;
738int L;
739
740// A1/A2: write L, then wait for barrier, then sleep
741void a1() {
742  L = 1;
743  pthread_barrier_wait(&B);
744  sleep(1);
745}
746void a2() {
747  pthread_barrier_wait(&B);
748  sleep(1);
749}
750
751// B1/B2: sleep, wait for barrier, then write L
752void b1() {
753  sleep(1);
754  pthread_barrier_wait(&B);
755  L = 1;
756}
757void b2() {
758  sleep(1);
759  pthread_barrier_wait(&B);
760}
761
762TEST(PositiveTests, CyclicBarrierTest) {
763  ANNOTATE_EXPECT_RACE_FOR_TSAN(&L, "real race, may be hidden"
764                                " by incorrect implementation of barrier");
765  pthread_barrier_init(&B, NULL, 3);
766  MyThreadArray t1(a1, a2, a2),
767                t2(b1, b2, b2);
768  t1.Start();
769  t2.Start();
770  t1.Join();
771  t2.Join();
772}
773
774
775int *G = NULL;
776
777void Worker() {
778  pthread_barrier_wait(&B);
779  (*G) = 1;
780  pthread_barrier_wait(&B);
781}
782
783TEST(PositiveTests, CyclicBarrierTwoCallsTest) {
784  pthread_barrier_init(&B, NULL, 2);
785  G = new int(0);
786  ANNOTATE_TRACE_MEMORY(G);
787  ANNOTATE_EXPECT_RACE_FOR_TSAN(G, "real race, may be hidden"
788                                " by incorrect implementation of barrier");
789  MyThreadArray t1(Worker, Worker);
790  t1.Start();
791  t1.Join();
792  CHECK(*G == 1);
793  delete G;
794}
795
796
797
798#endif  // NO_BARRIER
799}  // namespace
800
801TEST(NegativeTests, Mmap84GTest) {  // {{{1
802#ifdef ARCH_amd64
803#ifdef OS_linux
804  // test that we can mmap 84G and can do it fast.
805  size_t size = (1ULL << 32) * 21;  // 21 * 4G
806  void *mem_ptr = mmap((void *) 0,
807                       size,
808                       PROT_EXEC | PROT_READ | PROT_WRITE,
809                       MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE,
810                       -1,
811                       (off_t) 0);
812  printf("res=%p\n", mem_ptr);
813#endif
814#endif
815}
816
817namespace NegativeTests_PthreadCreateFailureTest {  // {{{1
818#ifdef OS_linux
819void* ThreadRoutine(void *) {
820  return NULL;
821}
822
823TEST(NegativeTests, PthreadCreateFailureTest) {
824  pthread_attr_t attributes;
825  pthread_attr_init(&attributes);
826  pthread_attr_setstacksize(&attributes, -1);
827  pthread_t handle;
828  CHECK(pthread_create(&handle, &attributes, ThreadRoutine, NULL) != 0);
829  pthread_attr_destroy(&attributes);
830}
831#endif  // OS_linux
832}  // namespace NegativeTests_PthreadCreateFailureTest
833
834namespace Signals {  // {{{1
835
836typedef void (*Sigaction)(int, siginfo_t *, void *);
837
838int     GLOB = 0;
839
840static void EnableSigprof(Sigaction SignalHandler) {
841  struct sigaction sa;
842  sa.sa_sigaction = SignalHandler;
843  sa.sa_flags = SA_RESTART | SA_SIGINFO;
844  sigemptyset(&sa.sa_mask);
845  if (sigaction(SIGPROF, &sa, NULL) != 0) {
846    perror("sigaction");
847    abort();
848  }
849  struct itimerval timer;
850  timer.it_interval.tv_sec = 0;
851  timer.it_interval.tv_usec = 1000000 / 10000;
852  timer.it_value = timer.it_interval;
853  if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
854    perror("setitimer");
855    abort();
856  }
857}
858
859static void DisableSigprof() {
860  // Disable the profiling timer.
861  struct itimerval timer;
862  timer.it_interval.tv_sec = 0;
863  timer.it_interval.tv_usec = 0;
864  timer.it_value = timer.it_interval;
865  if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
866    perror("setitimer");
867    abort();
868  }
869  // Ignore SIGPROFs from now on.
870  struct sigaction sa;
871  sa.sa_handler = SIG_IGN;
872  sa.sa_flags = SA_RESTART | SA_SIGINFO;
873  sigemptyset(&sa.sa_mask);
874  if (sigaction(SIGPROF, &sa, NULL) != 0) {
875    perror("sigaction");
876    abort();
877  }
878}
879
880void MallocTestWorker() {
881  for (int i = 0; i < 100000; i++) {
882    void *x = malloc((i % 64) + 1);
883    free (x);
884  }
885}
886
887// Regression test for
888// http://code.google.com/p/data-race-test/issues/detail?id=13 .
889// Make sure that locking events are handled in signal handlers.
890//
891// For some reason, invoking the signal handlers causes deadlocks on Mac OS.
892#ifndef __APPLE__
893Mutex mu;
894
895void SignalHandlerWithMutex(int, siginfo_t*, void*) {
896  mu.Lock();
897  GLOB++;
898  mu.Unlock();
899}
900
901TEST(Signals, SignalsAndMallocTestWithMutex) {
902  EnableSigprof(SignalHandlerWithMutex);
903  MyThreadArray t(MallocTestWorker, MallocTestWorker, MallocTestWorker);
904  t.Start();
905  t.Join();
906  printf("\tGLOB=%d\n", GLOB);
907  DisableSigprof();
908}
909#endif
910
911// Another regression test for
912// http://code.google.com/p/data-race-test/issues/detail?id=13 .
913// Make sure that locking events are handled in signal handlers.
914SpinLock sl;
915
916void SignalHandlerWithSpinlock(int, siginfo_t*, void*) {
917  sl.Lock();
918  GLOB++;
919  sl.Unlock();
920}
921
922TEST(Signals, DISABLED_SignalsAndMallocTestWithSpinlock) {
923  EnableSigprof(SignalHandlerWithSpinlock);
924  MyThreadArray t(MallocTestWorker, MallocTestWorker, MallocTestWorker);
925  t.Start();
926  t.Join();
927  printf("\tGLOB=%d\n", GLOB);
928  DisableSigprof();
929}
930
931// Regression test for
932// http://code.google.com/p/data-race-test/issues/detail?id=14.
933static void WaitTestSignalHandler(int, siginfo_t*, void*) {
934  ANNOTATE_HAPPENS_AFTER((void*)0x1234);
935}
936
937void WaitTestWorker() {
938  for (int i = 0; i < 1000000; i++) {
939    ANNOTATE_HAPPENS_AFTER((void*)0x1234);
940  }
941}
942
943TEST(Signals, SignalsAndWaitTest) {
944  EnableSigprof(WaitTestSignalHandler);
945  MyThreadArray t(WaitTestWorker, WaitTestWorker, WaitTestWorker);
946  t.Start();
947  t.Join();
948  DisableSigprof();
949}
950
951#ifndef __APPLE__
952// this test crashes on Mac in debug TSan build, see
953// http://code.google.com/p/data-race-test/issues/detail?id=47
954pid_t child_pid = 0;
955
956void child_handler(int signum) {
957  if (signum == SIGCHLD && child_pid == 0) {
958    printf("Whoops, PID shouldn't be 0!\n");
959  }
960}
961
962TEST(Signals, PositiveTests_RaceInSignal) {
963  // Currently the data race on child_pid can't be found,
964  // see http://code.google.com/p/data-race-test/issues/detail?id=46
965  //ANNOTATE_EXPECT_RACE(&child_pid, "Race on pid: fork vs signal handler");
966  signal(SIGCHLD, child_handler);
967  child_pid = fork();
968  if (child_pid == 0) {
969    // in child
970    exit(0);
971  }
972  wait(NULL);
973}
974#endif  // __APPLE__
975
976}  // namespace;
977
978TEST(WeirdSizesTests, FegetenvTest) {
979  // http://code.google.com/p/data-race-test/issues/detail?id=36
980  fenv_t tmp;
981  if (fegetenv(&tmp) != 0)
982    FAIL() << "fegetenv failed";
983}
984
985namespace NegativeTests_epoll {  // {{{1
986#ifdef OS_linux
987int GLOB;
988
989// Currently, ThreadSanitizer should create hb arcs between
990// epoll_ctl and epoll_wait regardless of the parameters. Check that.
991
992void Worker1() {
993  GLOB++;
994  struct epoll_event event;
995  epoll_ctl(0, 0, 0, &event);
996}
997void Worker2() {
998  struct epoll_event event;
999  epoll_wait(0, &event, 0, 0);
1000  GLOB++;
1001}
1002
1003TEST(NegativeTests,epollTest) {
1004  MyThreadArray mta(Worker1, Worker2);
1005  mta.Start();
1006  mta.Join();
1007}
1008#endif  // OS_linux
1009}
1010namespace NegativeTests_LockfTest {  // {{{1
1011
1012class ShmMutex {
1013 public:
1014  ShmMutex() : fd_(-1) { }
1015  void set_fd(int fd) {
1016    CHECK(fd_ == -1);
1017    fd_ = fd;
1018  }
1019  void Lock() {
1020    LockOrUnlockInternal(true);
1021  }
1022  void Unlock() {
1023    LockOrUnlockInternal(false);
1024  }
1025 private:
1026  void LockOrUnlockInternal(bool lock) {
1027    CHECK(fd_ >= 0);
1028    while (lockf(fd_, lock ? F_LOCK : F_ULOCK, 0) < 0) {
1029      if (errno == EINTR) {
1030        continue;
1031      } else if (errno == ENOLCK) {
1032        usleep(5000);
1033        continue;
1034      }
1035      CHECK(0);
1036    }
1037
1038  }
1039
1040  int fd_;
1041} mu;
1042
1043int GLOB;
1044
1045void Worker() {
1046  mu.Lock();
1047  GLOB++;
1048  mu.Unlock();
1049}
1050
1051TEST(NegativeTests,DISABLED_LockfTest) {
1052  mu.set_fd(1 /* stdout */);
1053  MyThreadArray mta(Worker, Worker);
1054  mta.Start();
1055  mta.Join();
1056}
1057
1058}
1059namespace PositiveTests_LockThenNoLock {  // {{{1
1060// Regression test for a bug fixed by r2312
1061int GLOB;
1062pthread_mutex_t mu;
1063StealthNotification n1, n2;
1064
1065void Worker1() {
1066  pthread_mutex_lock(&mu);
1067  GLOB = 1;
1068  pthread_mutex_unlock(&mu);
1069  n1.signal();
1070  n2.wait();
1071  GLOB = 2;
1072}
1073
1074void Worker2() {
1075  pthread_mutex_lock(&mu);
1076  GLOB = 3;
1077  pthread_mutex_unlock(&mu);
1078  n2.signal();
1079  n1.wait();
1080  GLOB = 4;
1081}
1082
1083TEST(PositiveTests, LockThenNoLock) {
1084  pthread_mutex_init(&mu, NULL);
1085  ANNOTATE_TRACE_MEMORY(&GLOB);
1086  ANNOTATE_EXPECT_RACE(&GLOB, "race");
1087  ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(&mu);
1088  MyThreadArray t(Worker1, Worker2);
1089  t.Start();
1090  t.Join();
1091  pthread_mutex_destroy(&mu);
1092}
1093}  // namespace
1094
1095#ifdef __APPLE__
1096namespace NegativeTests_PthreadCondWaitRelativeNp {  // {{{1
1097int GLOB = 0;
1098pthread_mutex_t mu;
1099pthread_cond_t cv;
1100
1101void Waiter() {
1102  struct timespec tv = {1000, 1000};
1103  pthread_mutex_lock(&mu);
1104  pthread_cond_timedwait_relative_np(&cv, &mu, &tv);
1105  GLOB = 2;
1106  pthread_mutex_unlock(&mu);
1107}
1108
1109void Waker() {
1110  pthread_mutex_lock(&mu);
1111  GLOB = 1;
1112  pthread_cond_signal(&cv);
1113  pthread_mutex_unlock(&mu);
1114}
1115
1116TEST(NegativeTests, PthreadCondWaitRelativeNpTest) {
1117  pthread_mutex_init(&mu, NULL);
1118  pthread_cond_init(&cv, NULL);
1119  MyThreadArray t(Waiter, Waker);
1120  t.Start();
1121  t.Join();
1122  pthread_mutex_destroy(&mu);
1123  pthread_cond_destroy(&cv);
1124}
1125}  // namespace
1126#endif  // __APPLE__
1127
1128namespace PositiveTests_RWLockVsRWLockTest {  // {{{1
1129// Test that reader lock/unlock do not create a hb-arc.
1130RWLock mu;
1131int GLOB;
1132StealthNotification n;
1133
1134void Thread1() {
1135  GLOB = 1;
1136  mu.ReaderLock();
1137  mu.ReaderUnlock();
1138  n.signal();
1139}
1140
1141void Thread2() {
1142  n.wait();
1143  mu.ReaderLock();
1144  mu.ReaderUnlock();
1145  GLOB = 1;
1146}
1147
1148TEST(PositiveTests, RWLockVsRWLockTest) {
1149  ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&mu);
1150  ANNOTATE_EXPECT_RACE(&GLOB, "rwunlock/rwlock is not a hb-arc");
1151  MyThreadArray t(Thread1, Thread2);
1152  t.Start();
1153  t.Join();
1154}
1155
1156}  // namespace
1157
1158namespace TSDTests {
1159// Test the support for libpthread TSD destructors.
1160pthread_key_t key;
1161const int kInitialValue = 0xfeedface;
1162int tsd_array[2];
1163
1164void Destructor(void *ptr) {
1165  int *write = (int*) ptr;
1166  *write = kInitialValue;
1167}
1168
1169void DoWork(int index) {
1170  int *value = &(tsd_array[index]);
1171  *value = 42;
1172  pthread_setspecific(key, value);
1173  int *read = (int*) pthread_getspecific(key);
1174  CHECK(read == value);
1175}
1176
1177void Worker0() { DoWork(0); }
1178void Worker1() { DoWork(1); }
1179
1180TEST(TSDTests, TSDDestructorTest) {
1181  pthread_key_create(&key, Destructor);
1182  MyThreadArray t(Worker0, Worker1);
1183  t.Start();
1184  t.Join();
1185  for (int i = 0; i < 2; ++i) {
1186    CHECK(tsd_array[i] == kInitialValue);
1187  }
1188}
1189
1190}
1191
1192// End {{{1
1193 // vim:shiftwidth=2:softtabstop=2:expandtab:foldmethod=marker
1194